mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-04 23:37:41 +02:00
Add root node in file tree (#4346)
- **PR Description** If files at the root level of the repository have changed, there was no way to see the combined diff of all of them. Fix this by inserting a `/` item in this case. This is useful in repositories such as git.git, which have all their `.c` files at root level (gasp). If only files inside some folder have changed, the root item gets compressed away automatically, so nothing changes for that case (which I guess should be more common for most people). Addresses #4331. - **Please check if the PR fulfills these requirements** * [x] Cheatsheets are up-to-date (run `go generate ./...`) * [x] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting)) * [x] Tests have been added/updated (see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md) for the integration test guide) * [ ] Text is internationalised (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation)) * [ ] If a new UserConfig entry was added, make sure it can be hot-reloaded (see [here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig)) * [ ] Docs have been updated if necessary * [x] You've read through your own file changes for silly mistakes etc
This commit is contained in:
commit
1107462c3e
@ -55,7 +55,7 @@ func getCommitFilesFromFilenames(filenames string) []*models.CommitFile {
|
||||
return lo.Map(lo.Chunk(lines, 2), func(chunk []string, _ int) *models.CommitFile {
|
||||
return &models.CommitFile{
|
||||
ChangeStatus: chunk[0],
|
||||
Name: chunk[1],
|
||||
Path: chunk[1],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ func TestGetCommitFilesFromFilenames(t *testing.T) {
|
||||
input: "MM\x00Myfile\x00",
|
||||
output: []*models.CommitFile{
|
||||
{
|
||||
Name: "Myfile",
|
||||
Path: "Myfile",
|
||||
ChangeStatus: "MM",
|
||||
},
|
||||
},
|
||||
@ -33,11 +33,11 @@ func TestGetCommitFilesFromFilenames(t *testing.T) {
|
||||
input: "MM\x00Myfile\x00M \x00MyOtherFile\x00",
|
||||
output: []*models.CommitFile{
|
||||
{
|
||||
Name: "Myfile",
|
||||
Path: "Myfile",
|
||||
ChangeStatus: "MM",
|
||||
},
|
||||
{
|
||||
Name: "MyOtherFile",
|
||||
Path: "MyOtherFile",
|
||||
ChangeStatus: "M ",
|
||||
},
|
||||
},
|
||||
@ -47,15 +47,15 @@ func TestGetCommitFilesFromFilenames(t *testing.T) {
|
||||
input: "MM\x00Myfile\x00M \x00MyOtherFile\x00 M\x00YetAnother\x00",
|
||||
output: []*models.CommitFile{
|
||||
{
|
||||
Name: "Myfile",
|
||||
Path: "Myfile",
|
||||
ChangeStatus: "MM",
|
||||
},
|
||||
{
|
||||
Name: "MyOtherFile",
|
||||
Path: "MyOtherFile",
|
||||
ChangeStatus: "M ",
|
||||
},
|
||||
{
|
||||
Name: "YetAnother",
|
||||
Path: "YetAnother",
|
||||
ChangeStatus: " M",
|
||||
},
|
||||
},
|
||||
|
@ -68,12 +68,12 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
|
||||
}
|
||||
|
||||
file := &models.File{
|
||||
Name: status.Name,
|
||||
PreviousName: status.PreviousName,
|
||||
Path: status.Path,
|
||||
PreviousPath: status.PreviousPath,
|
||||
DisplayString: status.StatusString,
|
||||
}
|
||||
|
||||
if diff, ok := fileDiffs[status.Name]; ok {
|
||||
if diff, ok := fileDiffs[status.Path]; ok {
|
||||
file.LinesAdded = diff.LinesAdded
|
||||
file.LinesDeleted = diff.LinesDeleted
|
||||
}
|
||||
@ -87,7 +87,7 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
|
||||
worktreePaths := linkedWortkreePaths(self.Fs, self.repoPaths.RepoGitDirPath())
|
||||
for _, file := range files {
|
||||
for _, worktreePath := range worktreePaths {
|
||||
absFilePath, err := filepath.Abs(file.Name)
|
||||
absFilePath, err := filepath.Abs(file.Path)
|
||||
if err != nil {
|
||||
self.Log.Error(err)
|
||||
continue
|
||||
@ -96,7 +96,7 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
|
||||
file.IsWorktree = true
|
||||
// `git status` renders this worktree as a folder with a trailing slash but we'll represent it as a singular worktree
|
||||
// If we include the slash, it will be rendered as a folder with a null file inside.
|
||||
file.Name = strings.TrimSuffix(file.Name, "/")
|
||||
file.Path = strings.TrimSuffix(file.Path, "/")
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -153,8 +153,8 @@ type GitStatusOptions struct {
|
||||
type FileStatus struct {
|
||||
StatusString string
|
||||
Change string // ??, MM, AM, ...
|
||||
Name string
|
||||
PreviousName string
|
||||
Path string
|
||||
PreviousPath string
|
||||
}
|
||||
|
||||
func (fileLoader *FileLoader) gitDiffNumStat() (string, error) {
|
||||
@ -197,14 +197,14 @@ func (self *FileLoader) gitStatus(opts GitStatusOptions) ([]FileStatus, error) {
|
||||
status := FileStatus{
|
||||
StatusString: original,
|
||||
Change: original[:2],
|
||||
Name: original[3:],
|
||||
PreviousName: "",
|
||||
Path: original[3:],
|
||||
PreviousPath: "",
|
||||
}
|
||||
|
||||
if strings.HasPrefix(status.Change, "R") {
|
||||
// if a line starts with 'R' then the next line is the original file.
|
||||
status.PreviousName = splitLines[i+1]
|
||||
status.StatusString = fmt.Sprintf("%s %s -> %s", status.Change, status.PreviousName, status.Name)
|
||||
status.PreviousPath = splitLines[i+1]
|
||||
status.StatusString = fmt.Sprintf("%s %s -> %s", status.Change, status.PreviousPath, status.Path)
|
||||
i++
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
showNumstatInFilesView: true,
|
||||
expectedFiles: []*models.File{
|
||||
{
|
||||
Name: "file1.txt",
|
||||
Path: "file1.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: true,
|
||||
@ -55,7 +55,7 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
LinesDeleted: 1,
|
||||
},
|
||||
{
|
||||
Name: "file3.txt",
|
||||
Path: "file3.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: false,
|
||||
Tracked: false,
|
||||
@ -69,7 +69,7 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
LinesDeleted: 2,
|
||||
},
|
||||
{
|
||||
Name: "file2.txt",
|
||||
Path: "file2.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: false,
|
||||
@ -83,7 +83,7 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
LinesDeleted: 0,
|
||||
},
|
||||
{
|
||||
Name: "file4.txt",
|
||||
Path: "file4.txt",
|
||||
HasStagedChanges: false,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: false,
|
||||
@ -97,7 +97,7 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
LinesDeleted: 2,
|
||||
},
|
||||
{
|
||||
Name: "file5.txt",
|
||||
Path: "file5.txt",
|
||||
HasStagedChanges: false,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: true,
|
||||
@ -119,7 +119,7 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"}, "MM a\nb.txt", nil),
|
||||
expectedFiles: []*models.File{
|
||||
{
|
||||
Name: "a\nb.txt",
|
||||
Path: "a\nb.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: true,
|
||||
@ -142,8 +142,8 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
),
|
||||
expectedFiles: []*models.File{
|
||||
{
|
||||
Name: "after1.txt",
|
||||
PreviousName: "before1.txt",
|
||||
Path: "after1.txt",
|
||||
PreviousPath: "before1.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: false,
|
||||
Tracked: true,
|
||||
@ -155,8 +155,8 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
ShortStatus: "R ",
|
||||
},
|
||||
{
|
||||
Name: "after2.txt",
|
||||
PreviousName: "before2.txt",
|
||||
Path: "after2.txt",
|
||||
PreviousPath: "before2.txt",
|
||||
HasStagedChanges: true,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: true,
|
||||
@ -179,7 +179,7 @@ func TestFileGetStatusFiles(t *testing.T) {
|
||||
),
|
||||
expectedFiles: []*models.File{
|
||||
{
|
||||
Name: "a -> b.txt",
|
||||
Path: "a -> b.txt",
|
||||
HasStagedChanges: false,
|
||||
HasUnstagedChanges: true,
|
||||
Tracked: false,
|
||||
|
@ -92,11 +92,11 @@ func (self *WorkingTreeCommands) BeforeAndAfterFileForRename(file *models.File)
|
||||
var beforeFile *models.File
|
||||
var afterFile *models.File
|
||||
for _, f := range filesWithoutRenames {
|
||||
if f.Name == file.PreviousName {
|
||||
if f.Path == file.PreviousPath {
|
||||
beforeFile = f
|
||||
}
|
||||
|
||||
if f.Name == file.Name {
|
||||
if f.Path == file.Path {
|
||||
afterFile = f
|
||||
}
|
||||
}
|
||||
@ -134,13 +134,13 @@ func (self *WorkingTreeCommands) DiscardAllFileChanges(file *models.File) error
|
||||
|
||||
if file.ShortStatus == "AA" {
|
||||
if err := self.cmd.New(
|
||||
NewGitCmd("checkout").Arg("--ours", "--", file.Name).ToArgv(),
|
||||
NewGitCmd("checkout").Arg("--ours", "--", file.Path).ToArgv(),
|
||||
).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.cmd.New(
|
||||
NewGitCmd("add").Arg("--", file.Name).ToArgv(),
|
||||
NewGitCmd("add").Arg("--", file.Path).ToArgv(),
|
||||
).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -149,14 +149,14 @@ func (self *WorkingTreeCommands) DiscardAllFileChanges(file *models.File) error
|
||||
|
||||
if file.ShortStatus == "DU" {
|
||||
return self.cmd.New(
|
||||
NewGitCmd("rm").Arg("--", file.Name).ToArgv(),
|
||||
NewGitCmd("rm").Arg("--", file.Path).ToArgv(),
|
||||
).Run()
|
||||
}
|
||||
|
||||
// if the file isn't tracked, we assume you want to delete it
|
||||
if file.HasStagedChanges || file.HasMergeConflicts {
|
||||
if err := self.cmd.New(
|
||||
NewGitCmd("reset").Arg("--", file.Name).ToArgv(),
|
||||
NewGitCmd("reset").Arg("--", file.Path).ToArgv(),
|
||||
).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -167,7 +167,7 @@ func (self *WorkingTreeCommands) DiscardAllFileChanges(file *models.File) error
|
||||
}
|
||||
|
||||
if file.Added {
|
||||
return self.os.RemoveFile(file.Name)
|
||||
return self.os.RemoveFile(file.Path)
|
||||
}
|
||||
|
||||
return self.DiscardUnstagedFileChanges(file)
|
||||
@ -199,7 +199,7 @@ func (self *WorkingTreeCommands) DiscardUnstagedDirChanges(node IFileNode) error
|
||||
}
|
||||
} else {
|
||||
if file.Added && !file.HasStagedChanges {
|
||||
return self.os.RemoveFile(file.Name)
|
||||
return self.os.RemoveFile(file.Path)
|
||||
}
|
||||
|
||||
if err := self.DiscardUnstagedFileChanges(file); err != nil {
|
||||
@ -226,7 +226,7 @@ func (self *WorkingTreeCommands) RemoveUntrackedDirFiles(node IFileNode) error {
|
||||
}
|
||||
|
||||
func (self *WorkingTreeCommands) DiscardUnstagedFileChanges(file *models.File) error {
|
||||
cmdArgs := NewGitCmd("checkout").Arg("--", file.Name).ToArgv()
|
||||
cmdArgs := NewGitCmd("checkout").Arg("--", file.Path).ToArgv()
|
||||
return self.cmd.New(cmdArgs).Run()
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
||||
{
|
||||
testName: "An error occurred when resetting",
|
||||
file: &models.File{
|
||||
Name: "test",
|
||||
Path: "test",
|
||||
HasStagedChanges: true,
|
||||
},
|
||||
removeFile: func(string) error { return nil },
|
||||
@ -94,7 +94,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
||||
{
|
||||
testName: "An error occurred when removing file",
|
||||
file: &models.File{
|
||||
Name: "test",
|
||||
Path: "test",
|
||||
Tracked: false,
|
||||
Added: true,
|
||||
},
|
||||
@ -107,7 +107,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
||||
{
|
||||
testName: "An error occurred with checkout",
|
||||
file: &models.File{
|
||||
Name: "test",
|
||||
Path: "test",
|
||||
Tracked: true,
|
||||
HasStagedChanges: false,
|
||||
},
|
||||
@ -119,7 +119,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
||||
{
|
||||
testName: "Checkout only",
|
||||
file: &models.File{
|
||||
Name: "test",
|
||||
Path: "test",
|
||||
Tracked: true,
|
||||
HasStagedChanges: false,
|
||||
},
|
||||
@ -131,7 +131,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
||||
{
|
||||
testName: "Reset and checkout staged changes",
|
||||
file: &models.File{
|
||||
Name: "test",
|
||||
Path: "test",
|
||||
Tracked: true,
|
||||
HasStagedChanges: true,
|
||||
},
|
||||
@ -144,7 +144,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
||||
{
|
||||
testName: "Reset and checkout merge conflicts",
|
||||
file: &models.File{
|
||||
Name: "test",
|
||||
Path: "test",
|
||||
Tracked: true,
|
||||
HasMergeConflicts: true,
|
||||
},
|
||||
@ -157,7 +157,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
||||
{
|
||||
testName: "Reset and remove",
|
||||
file: &models.File{
|
||||
Name: "test",
|
||||
Path: "test",
|
||||
Tracked: false,
|
||||
Added: true,
|
||||
HasStagedChanges: true,
|
||||
@ -173,7 +173,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
||||
{
|
||||
testName: "Remove only",
|
||||
file: &models.File{
|
||||
Name: "test",
|
||||
Path: "test",
|
||||
Tracked: false,
|
||||
Added: true,
|
||||
HasStagedChanges: false,
|
||||
@ -220,7 +220,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
||||
{
|
||||
testName: "Default case",
|
||||
file: &models.File{
|
||||
Name: "test.txt",
|
||||
Path: "test.txt",
|
||||
HasStagedChanges: false,
|
||||
Tracked: true,
|
||||
},
|
||||
@ -235,7 +235,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
||||
{
|
||||
testName: "cached",
|
||||
file: &models.File{
|
||||
Name: "test.txt",
|
||||
Path: "test.txt",
|
||||
HasStagedChanges: false,
|
||||
Tracked: true,
|
||||
},
|
||||
@ -250,7 +250,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
||||
{
|
||||
testName: "plain",
|
||||
file: &models.File{
|
||||
Name: "test.txt",
|
||||
Path: "test.txt",
|
||||
HasStagedChanges: false,
|
||||
Tracked: true,
|
||||
},
|
||||
@ -265,7 +265,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
||||
{
|
||||
testName: "File not tracked and file has no staged changes",
|
||||
file: &models.File{
|
||||
Name: "test.txt",
|
||||
Path: "test.txt",
|
||||
HasStagedChanges: false,
|
||||
Tracked: false,
|
||||
},
|
||||
@ -280,7 +280,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
||||
{
|
||||
testName: "Default case (ignore whitespace)",
|
||||
file: &models.File{
|
||||
Name: "test.txt",
|
||||
Path: "test.txt",
|
||||
HasStagedChanges: false,
|
||||
Tracked: true,
|
||||
},
|
||||
@ -295,7 +295,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
||||
{
|
||||
testName: "Show diff with custom context size",
|
||||
file: &models.File{
|
||||
Name: "test.txt",
|
||||
Path: "test.txt",
|
||||
HasStagedChanges: false,
|
||||
Tracked: true,
|
||||
},
|
||||
@ -310,7 +310,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
||||
{
|
||||
testName: "Show diff with custom similarity threshold",
|
||||
file: &models.File{
|
||||
Name: "test.txt",
|
||||
Path: "test.txt",
|
||||
HasStagedChanges: false,
|
||||
Tracked: true,
|
||||
},
|
||||
@ -466,7 +466,7 @@ func TestWorkingTreeDiscardUnstagedFileChanges(t *testing.T) {
|
||||
scenarios := []scenario{
|
||||
{
|
||||
testName: "valid case",
|
||||
file: &models.File{Name: "test.txt"},
|
||||
file: &models.File{Path: "test.txt"},
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"checkout", "--", "test.txt"}, "", nil),
|
||||
test: func(err error) {
|
||||
|
@ -2,18 +2,17 @@ package models
|
||||
|
||||
// CommitFile : A git commit file
|
||||
type CommitFile struct {
|
||||
// TODO: rename this to Path
|
||||
Name string
|
||||
Path string
|
||||
|
||||
ChangeStatus string // e.g. 'A' for added or 'M' for modified. This is based on the result from git diff --name-status
|
||||
}
|
||||
|
||||
func (f *CommitFile) ID() string {
|
||||
return f.Name
|
||||
return f.Path
|
||||
}
|
||||
|
||||
func (f *CommitFile) Description() string {
|
||||
return f.Name
|
||||
return f.Path
|
||||
}
|
||||
|
||||
func (f *CommitFile) Added() bool {
|
||||
@ -25,5 +24,5 @@ func (f *CommitFile) Deleted() bool {
|
||||
}
|
||||
|
||||
func (f *CommitFile) GetPath() string {
|
||||
return f.Name
|
||||
return f.Path
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ import (
|
||||
// File : A file from git status
|
||||
// duplicating this for now
|
||||
type File struct {
|
||||
Name string
|
||||
PreviousName string
|
||||
Path string
|
||||
PreviousPath string
|
||||
HasStagedChanges bool
|
||||
HasUnstagedChanges bool
|
||||
Tracked bool
|
||||
@ -37,14 +37,14 @@ type IFile interface {
|
||||
}
|
||||
|
||||
func (f *File) IsRename() bool {
|
||||
return f.PreviousName != ""
|
||||
return f.PreviousPath != ""
|
||||
}
|
||||
|
||||
// Names returns an array containing just the filename, or in the case of a rename, the after filename and the before filename
|
||||
func (f *File) Names() []string {
|
||||
result := []string{f.Name}
|
||||
if f.PreviousName != "" {
|
||||
result = append(result, f.PreviousName)
|
||||
result := []string{f.Path}
|
||||
if f.PreviousPath != "" {
|
||||
result = append(result, f.PreviousPath)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -55,11 +55,11 @@ func (f *File) Matches(f2 *File) bool {
|
||||
}
|
||||
|
||||
func (f *File) ID() string {
|
||||
return f.Name
|
||||
return f.Path
|
||||
}
|
||||
|
||||
func (f *File) Description() string {
|
||||
return f.Name
|
||||
return f.Path
|
||||
}
|
||||
|
||||
func (f *File) IsSubmodule(configs []*SubmoduleConfig) bool {
|
||||
@ -68,7 +68,7 @@ func (f *File) IsSubmodule(configs []*SubmoduleConfig) bool {
|
||||
|
||||
func (f *File) SubmoduleConfig(configs []*SubmoduleConfig) *SubmoduleConfig {
|
||||
for _, config := range configs {
|
||||
if f.Name == config.Path {
|
||||
if f.Path == config.Path {
|
||||
return config
|
||||
}
|
||||
}
|
||||
@ -90,11 +90,11 @@ func (f *File) GetIsTracked() bool {
|
||||
|
||||
func (f *File) GetPath() string {
|
||||
// TODO: remove concept of name; just use path
|
||||
return f.Name
|
||||
return f.Path
|
||||
}
|
||||
|
||||
func (f *File) GetPreviousPath() string {
|
||||
return f.PreviousName
|
||||
return f.PreviousPath
|
||||
}
|
||||
|
||||
func (f *File) GetIsFile() bool {
|
||||
|
@ -231,7 +231,7 @@ func (self *CommitFilesController) openCopyMenu() error {
|
||||
copyPathItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyFilePath,
|
||||
OnPress: func() error {
|
||||
if err := self.c.OS().CopyToClipboard(node.Path); err != nil {
|
||||
if err := self.c.OS().CopyToClipboard(node.GetPath()); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Toast(self.c.Tr.FilePathCopiedToast)
|
||||
@ -402,7 +402,7 @@ func (self *CommitFilesController) toggleForPatch(selectedNodes []*filetree.Comm
|
||||
// Find if any file in the selection is unselected or partially added
|
||||
adding := lo.SomeBy(selectedNodes, func(node *filetree.CommitFileNode) bool {
|
||||
return node.SomeFile(func(file *models.CommitFile) bool {
|
||||
fileStatus := self.c.Git().Patch.PatchBuilder.GetFileStatus(file.Name, self.context().GetRef().RefName())
|
||||
fileStatus := self.c.Git().Patch.PatchBuilder.GetFileStatus(file.Path, self.context().GetRef().RefName())
|
||||
return fileStatus == patch.PART || fileStatus == patch.UNSELECTED
|
||||
})
|
||||
})
|
||||
@ -415,7 +415,7 @@ func (self *CommitFilesController) toggleForPatch(selectedNodes []*filetree.Comm
|
||||
|
||||
for _, node := range selectedNodes {
|
||||
err := node.ForEachFile(func(file *models.CommitFile) error {
|
||||
return patchOperationFunction(file.Name)
|
||||
return patchOperationFunction(file.Path)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -509,7 +509,7 @@ func (self *CommitFilesController) enterCommitFile(node *filetree.CommitFileNode
|
||||
}
|
||||
|
||||
func (self *CommitFilesController) handleToggleCommitFileDirCollapsed(node *filetree.CommitFileNode) error {
|
||||
self.context().CommitFileTreeViewModel.ToggleCollapsed(node.GetPath())
|
||||
self.context().CommitFileTreeViewModel.ToggleCollapsed(node.GetInternalPath())
|
||||
|
||||
self.c.PostRefreshUpdate(self.context())
|
||||
|
||||
|
@ -372,7 +372,7 @@ func (self *FilesController) optimisticChange(nodes []*filetree.FileNode, optimi
|
||||
err := node.ForEachFile(func(f *models.File) error {
|
||||
// can't act on the file itself: we need to update the original model file
|
||||
for _, modelFile := range self.c.Model().Files {
|
||||
if modelFile.Name == f.Name {
|
||||
if modelFile.Path == f.Path {
|
||||
if optimisticChangeFn(modelFile) {
|
||||
rerender = true
|
||||
}
|
||||
@ -410,7 +410,7 @@ func (self *FilesController) pressWithLock(selectedNodes []*filetree.FileNode) e
|
||||
|
||||
toPaths := func(nodes []*filetree.FileNode) []string {
|
||||
return lo.Map(nodes, func(node *filetree.FileNode, _ int) string {
|
||||
return node.Path
|
||||
return node.GetPath()
|
||||
})
|
||||
}
|
||||
|
||||
@ -881,7 +881,7 @@ func (self *FilesController) openDiffTool(node *filetree.FileNode) error {
|
||||
return self.c.RunSubprocessAndRefresh(
|
||||
self.c.Git().Diff.OpenDiffToolCmdObj(
|
||||
git_commands.DiffToolCmdOptions{
|
||||
Filepath: node.Path,
|
||||
Filepath: node.GetPath(),
|
||||
FromCommit: fromCommit,
|
||||
ToCommit: "",
|
||||
Reverse: reverse,
|
||||
@ -897,7 +897,7 @@ func (self *FilesController) switchToMerge() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return self.c.Helpers().MergeConflicts.SwitchToMerge(file.Name)
|
||||
return self.c.Helpers().MergeConflicts.SwitchToMerge(file.Path)
|
||||
}
|
||||
|
||||
func (self *FilesController) createStashMenu() error {
|
||||
@ -979,7 +979,7 @@ func (self *FilesController) openCopyMenu() error {
|
||||
copyPathItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyFilePath,
|
||||
OnPress: func() error {
|
||||
if err := self.c.OS().CopyToClipboard(node.Path); err != nil {
|
||||
if err := self.c.OS().CopyToClipboard(node.GetPath()); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Toast(self.c.Tr.FilePathCopiedToast)
|
||||
@ -1078,7 +1078,7 @@ func (self *FilesController) handleToggleDirCollapsed() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.context().FileTreeViewModel.ToggleCollapsed(node.GetPath())
|
||||
self.context().FileTreeViewModel.ToggleCollapsed(node.GetInternalPath())
|
||||
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().Files)
|
||||
|
||||
|
@ -554,11 +554,11 @@ func (self *RefreshHelper) refreshStateFiles() error {
|
||||
prevConflictFileCount++
|
||||
}
|
||||
if file.HasInlineMergeConflicts {
|
||||
hasConflicts, err := mergeconflicts.FileHasConflictMarkers(file.Name)
|
||||
hasConflicts, err := mergeconflicts.FileHasConflictMarkers(file.Path)
|
||||
if err != nil {
|
||||
self.c.Log.Error(err)
|
||||
} else if !hasConflicts {
|
||||
pathsToStage = append(pathsToStage, file.Name)
|
||||
pathsToStage = append(pathsToStage, file.Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ func BuildTreeFromFiles(files []*models.File) *Node[models.File] {
|
||||
|
||||
var curr *Node[models.File]
|
||||
for _, file := range files {
|
||||
splitPath := split(file.Name)
|
||||
splitPath := split("./" + file.Path)
|
||||
curr = root
|
||||
outer:
|
||||
for i := range splitPath {
|
||||
@ -40,8 +40,13 @@ func BuildTreeFromFiles(files []*models.File) *Node[models.File] {
|
||||
continue outer
|
||||
}
|
||||
|
||||
if i == 0 && len(files) == 1 && len(splitPath) == 2 {
|
||||
// skip the root item when there's only one file at top level; we don't need it in that case
|
||||
continue outer
|
||||
}
|
||||
|
||||
newChild := &Node[models.File]{
|
||||
Path: path,
|
||||
path: path,
|
||||
File: setFile,
|
||||
}
|
||||
curr.Children = append(curr.Children, newChild)
|
||||
@ -70,7 +75,7 @@ func BuildTreeFromCommitFiles(files []*models.CommitFile) *Node[models.CommitFil
|
||||
|
||||
var curr *Node[models.CommitFile]
|
||||
for _, file := range files {
|
||||
splitPath := split(file.Name)
|
||||
splitPath := split("./" + file.Path)
|
||||
curr = root
|
||||
outer:
|
||||
for i := range splitPath {
|
||||
@ -83,14 +88,19 @@ func BuildTreeFromCommitFiles(files []*models.CommitFile) *Node[models.CommitFil
|
||||
path := join(splitPath[:i+1])
|
||||
|
||||
for _, existingChild := range curr.Children {
|
||||
if existingChild.Path == path {
|
||||
if existingChild.path == path {
|
||||
curr = existingChild
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
|
||||
if i == 0 && len(files) == 1 && len(splitPath) == 2 {
|
||||
// skip the root item when there's only one file at top level; we don't need it in that case
|
||||
continue outer
|
||||
}
|
||||
|
||||
newChild := &Node[models.CommitFile]{
|
||||
Path: path,
|
||||
path: path,
|
||||
File: setFile,
|
||||
}
|
||||
curr.Children = append(curr.Children, newChild)
|
||||
|
@ -17,7 +17,7 @@ func TestBuildTreeFromFiles(t *testing.T) {
|
||||
name: "no files",
|
||||
files: []*models.File{},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: nil,
|
||||
},
|
||||
},
|
||||
@ -25,25 +25,26 @@ func TestBuildTreeFromFiles(t *testing.T) {
|
||||
name: "files in same directory",
|
||||
files: []*models.File{
|
||||
{
|
||||
Name: "dir1/a",
|
||||
Path: "dir1/a",
|
||||
},
|
||||
{
|
||||
Name: "dir1/b",
|
||||
Path: "dir1/b",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
Path: "dir1",
|
||||
path: "./dir1",
|
||||
CompressionLevel: 1,
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "dir1/a"},
|
||||
Path: "dir1/a",
|
||||
File: &models.File{Path: "dir1/a"},
|
||||
path: "./dir1/a",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "dir1/b"},
|
||||
Path: "dir1/b",
|
||||
File: &models.File{Path: "dir1/b"},
|
||||
path: "./dir1/b",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -54,34 +55,39 @@ func TestBuildTreeFromFiles(t *testing.T) {
|
||||
name: "paths that can be compressed",
|
||||
files: []*models.File{
|
||||
{
|
||||
Name: "dir1/dir3/a",
|
||||
Path: "dir1/dir3/a",
|
||||
},
|
||||
{
|
||||
Name: "dir2/dir4/b",
|
||||
Path: "dir2/dir4/b",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
Path: "dir1/dir3",
|
||||
path: ".",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "dir1/dir3/a"},
|
||||
Path: "dir1/dir3/a",
|
||||
path: "./dir1/dir3",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Path: "dir1/dir3/a"},
|
||||
path: "./dir1/dir3/a",
|
||||
},
|
||||
},
|
||||
CompressionLevel: 1,
|
||||
},
|
||||
},
|
||||
CompressionLevel: 1,
|
||||
},
|
||||
{
|
||||
Path: "dir2/dir4",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "dir2/dir4/b"},
|
||||
Path: "dir2/dir4/b",
|
||||
path: "./dir2/dir4",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Path: "dir2/dir4/b"},
|
||||
path: "./dir2/dir4/b",
|
||||
},
|
||||
},
|
||||
CompressionLevel: 1,
|
||||
},
|
||||
},
|
||||
CompressionLevel: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -90,22 +96,27 @@ func TestBuildTreeFromFiles(t *testing.T) {
|
||||
name: "paths that can be sorted",
|
||||
files: []*models.File{
|
||||
{
|
||||
Name: "b",
|
||||
Path: "b",
|
||||
},
|
||||
{
|
||||
Name: "a",
|
||||
Path: "a",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "a"},
|
||||
Path: "a",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "b"},
|
||||
Path: "b",
|
||||
path: ".",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Path: "a"},
|
||||
path: "./a",
|
||||
},
|
||||
{
|
||||
File: &models.File{Path: "b"},
|
||||
path: "./b",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -114,32 +125,37 @@ func TestBuildTreeFromFiles(t *testing.T) {
|
||||
name: "paths that can be sorted including a merge conflict file",
|
||||
files: []*models.File{
|
||||
{
|
||||
Name: "b",
|
||||
Path: "b",
|
||||
},
|
||||
{
|
||||
Name: "z",
|
||||
Path: "z",
|
||||
HasMergeConflicts: true,
|
||||
},
|
||||
{
|
||||
Name: "a",
|
||||
Path: "a",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
// it is a little strange that we're not bubbling up our merge conflict
|
||||
// here but we are technically still in tree mode and that's the rule
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "a"},
|
||||
Path: "a",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "b"},
|
||||
Path: "b",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "z", HasMergeConflicts: true},
|
||||
Path: "z",
|
||||
path: ".",
|
||||
// it is a little strange that we're not bubbling up our merge conflict
|
||||
// here but we are technically still in tree mode and that's the rule
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Path: "a"},
|
||||
path: "./a",
|
||||
},
|
||||
{
|
||||
File: &models.File{Path: "b"},
|
||||
path: "./b",
|
||||
},
|
||||
{
|
||||
File: &models.File{Path: "z", HasMergeConflicts: true},
|
||||
path: "./z",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -164,7 +180,7 @@ func TestBuildFlatTreeFromFiles(t *testing.T) {
|
||||
name: "no files",
|
||||
files: []*models.File{},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{},
|
||||
},
|
||||
},
|
||||
@ -172,23 +188,23 @@ func TestBuildFlatTreeFromFiles(t *testing.T) {
|
||||
name: "files in same directory",
|
||||
files: []*models.File{
|
||||
{
|
||||
Name: "dir1/a",
|
||||
Path: "dir1/a",
|
||||
},
|
||||
{
|
||||
Name: "dir1/b",
|
||||
Path: "dir1/b",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "dir1/a"},
|
||||
Path: "dir1/a",
|
||||
File: &models.File{Path: "dir1/a"},
|
||||
path: "./dir1/a",
|
||||
CompressionLevel: 0,
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "dir1/b"},
|
||||
Path: "dir1/b",
|
||||
File: &models.File{Path: "dir1/b"},
|
||||
path: "./dir1/b",
|
||||
CompressionLevel: 0,
|
||||
},
|
||||
},
|
||||
@ -198,23 +214,23 @@ func TestBuildFlatTreeFromFiles(t *testing.T) {
|
||||
name: "paths that can be compressed",
|
||||
files: []*models.File{
|
||||
{
|
||||
Name: "dir1/a",
|
||||
Path: "dir1/a",
|
||||
},
|
||||
{
|
||||
Name: "dir2/b",
|
||||
Path: "dir2/b",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "dir1/a"},
|
||||
Path: "dir1/a",
|
||||
File: &models.File{Path: "dir1/a"},
|
||||
path: "./dir1/a",
|
||||
CompressionLevel: 0,
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "dir2/b"},
|
||||
Path: "dir2/b",
|
||||
File: &models.File{Path: "dir2/b"},
|
||||
path: "./dir2/b",
|
||||
CompressionLevel: 0,
|
||||
},
|
||||
},
|
||||
@ -224,22 +240,22 @@ func TestBuildFlatTreeFromFiles(t *testing.T) {
|
||||
name: "paths that can be sorted",
|
||||
files: []*models.File{
|
||||
{
|
||||
Name: "b",
|
||||
Path: "b",
|
||||
},
|
||||
{
|
||||
Name: "a",
|
||||
Path: "a",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "a"},
|
||||
Path: "a",
|
||||
File: &models.File{Path: "a"},
|
||||
path: "./a",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "b"},
|
||||
Path: "b",
|
||||
File: &models.File{Path: "b"},
|
||||
path: "./b",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -248,56 +264,56 @@ func TestBuildFlatTreeFromFiles(t *testing.T) {
|
||||
name: "tracked, untracked, and conflicted files",
|
||||
files: []*models.File{
|
||||
{
|
||||
Name: "a2",
|
||||
Path: "a2",
|
||||
Tracked: false,
|
||||
},
|
||||
{
|
||||
Name: "a1",
|
||||
Path: "a1",
|
||||
Tracked: false,
|
||||
},
|
||||
{
|
||||
Name: "c2",
|
||||
Path: "c2",
|
||||
HasMergeConflicts: true,
|
||||
},
|
||||
{
|
||||
Name: "c1",
|
||||
Path: "c1",
|
||||
HasMergeConflicts: true,
|
||||
},
|
||||
{
|
||||
Name: "b2",
|
||||
Path: "b2",
|
||||
Tracked: true,
|
||||
},
|
||||
{
|
||||
Name: "b1",
|
||||
Path: "b1",
|
||||
Tracked: true,
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "c1", HasMergeConflicts: true},
|
||||
Path: "c1",
|
||||
File: &models.File{Path: "c1", HasMergeConflicts: true},
|
||||
path: "./c1",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "c2", HasMergeConflicts: true},
|
||||
Path: "c2",
|
||||
File: &models.File{Path: "c2", HasMergeConflicts: true},
|
||||
path: "./c2",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "b1", Tracked: true},
|
||||
Path: "b1",
|
||||
File: &models.File{Path: "b1", Tracked: true},
|
||||
path: "./b1",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "b2", Tracked: true},
|
||||
Path: "b2",
|
||||
File: &models.File{Path: "b2", Tracked: true},
|
||||
path: "./b2",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "a1", Tracked: false},
|
||||
Path: "a1",
|
||||
File: &models.File{Path: "a1", Tracked: false},
|
||||
path: "./a1",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "a2", Tracked: false},
|
||||
Path: "a2",
|
||||
File: &models.File{Path: "a2", Tracked: false},
|
||||
path: "./a2",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -322,7 +338,7 @@ func TestBuildTreeFromCommitFiles(t *testing.T) {
|
||||
name: "no files",
|
||||
files: []*models.CommitFile{},
|
||||
expected: &Node[models.CommitFile]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: nil,
|
||||
},
|
||||
},
|
||||
@ -330,25 +346,26 @@ func TestBuildTreeFromCommitFiles(t *testing.T) {
|
||||
name: "files in same directory",
|
||||
files: []*models.CommitFile{
|
||||
{
|
||||
Name: "dir1/a",
|
||||
Path: "dir1/a",
|
||||
},
|
||||
{
|
||||
Name: "dir1/b",
|
||||
Path: "dir1/b",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.CommitFile]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
Path: "dir1",
|
||||
path: "./dir1",
|
||||
CompressionLevel: 1,
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Name: "dir1/a"},
|
||||
Path: "dir1/a",
|
||||
File: &models.CommitFile{Path: "dir1/a"},
|
||||
path: "./dir1/a",
|
||||
},
|
||||
{
|
||||
File: &models.CommitFile{Name: "dir1/b"},
|
||||
Path: "dir1/b",
|
||||
File: &models.CommitFile{Path: "dir1/b"},
|
||||
path: "./dir1/b",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -359,34 +376,39 @@ func TestBuildTreeFromCommitFiles(t *testing.T) {
|
||||
name: "paths that can be compressed",
|
||||
files: []*models.CommitFile{
|
||||
{
|
||||
Name: "dir1/dir3/a",
|
||||
Path: "dir1/dir3/a",
|
||||
},
|
||||
{
|
||||
Name: "dir2/dir4/b",
|
||||
Path: "dir2/dir4/b",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.CommitFile]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
Path: "dir1/dir3",
|
||||
path: ".",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Name: "dir1/dir3/a"},
|
||||
Path: "dir1/dir3/a",
|
||||
path: "./dir1/dir3",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Path: "dir1/dir3/a"},
|
||||
path: "./dir1/dir3/a",
|
||||
},
|
||||
},
|
||||
CompressionLevel: 1,
|
||||
},
|
||||
},
|
||||
CompressionLevel: 1,
|
||||
},
|
||||
{
|
||||
Path: "dir2/dir4",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Name: "dir2/dir4/b"},
|
||||
Path: "dir2/dir4/b",
|
||||
path: "./dir2/dir4",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Path: "dir2/dir4/b"},
|
||||
path: "./dir2/dir4/b",
|
||||
},
|
||||
},
|
||||
CompressionLevel: 1,
|
||||
},
|
||||
},
|
||||
CompressionLevel: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -395,22 +417,27 @@ func TestBuildTreeFromCommitFiles(t *testing.T) {
|
||||
name: "paths that can be sorted",
|
||||
files: []*models.CommitFile{
|
||||
{
|
||||
Name: "b",
|
||||
Path: "b",
|
||||
},
|
||||
{
|
||||
Name: "a",
|
||||
Path: "a",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.CommitFile]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Name: "a"},
|
||||
Path: "a",
|
||||
},
|
||||
{
|
||||
File: &models.CommitFile{Name: "b"},
|
||||
Path: "b",
|
||||
path: ".",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Path: "a"},
|
||||
path: "./a",
|
||||
},
|
||||
{
|
||||
File: &models.CommitFile{Path: "b"},
|
||||
path: "./b",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -435,7 +462,7 @@ func TestBuildFlatTreeFromCommitFiles(t *testing.T) {
|
||||
name: "no files",
|
||||
files: []*models.CommitFile{},
|
||||
expected: &Node[models.CommitFile]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.CommitFile]{},
|
||||
},
|
||||
},
|
||||
@ -443,23 +470,23 @@ func TestBuildFlatTreeFromCommitFiles(t *testing.T) {
|
||||
name: "files in same directory",
|
||||
files: []*models.CommitFile{
|
||||
{
|
||||
Name: "dir1/a",
|
||||
Path: "dir1/a",
|
||||
},
|
||||
{
|
||||
Name: "dir1/b",
|
||||
Path: "dir1/b",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.CommitFile]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Name: "dir1/a"},
|
||||
Path: "dir1/a",
|
||||
File: &models.CommitFile{Path: "dir1/a"},
|
||||
path: "./dir1/a",
|
||||
CompressionLevel: 0,
|
||||
},
|
||||
{
|
||||
File: &models.CommitFile{Name: "dir1/b"},
|
||||
Path: "dir1/b",
|
||||
File: &models.CommitFile{Path: "dir1/b"},
|
||||
path: "./dir1/b",
|
||||
CompressionLevel: 0,
|
||||
},
|
||||
},
|
||||
@ -469,23 +496,23 @@ func TestBuildFlatTreeFromCommitFiles(t *testing.T) {
|
||||
name: "paths that can be compressed",
|
||||
files: []*models.CommitFile{
|
||||
{
|
||||
Name: "dir1/a",
|
||||
Path: "dir1/a",
|
||||
},
|
||||
{
|
||||
Name: "dir2/b",
|
||||
Path: "dir2/b",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.CommitFile]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Name: "dir1/a"},
|
||||
Path: "dir1/a",
|
||||
File: &models.CommitFile{Path: "dir1/a"},
|
||||
path: "./dir1/a",
|
||||
CompressionLevel: 0,
|
||||
},
|
||||
{
|
||||
File: &models.CommitFile{Name: "dir2/b"},
|
||||
Path: "dir2/b",
|
||||
File: &models.CommitFile{Path: "dir2/b"},
|
||||
path: "./dir2/b",
|
||||
CompressionLevel: 0,
|
||||
},
|
||||
},
|
||||
@ -495,22 +522,22 @@ func TestBuildFlatTreeFromCommitFiles(t *testing.T) {
|
||||
name: "paths that can be sorted",
|
||||
files: []*models.CommitFile{
|
||||
{
|
||||
Name: "b",
|
||||
Path: "b",
|
||||
},
|
||||
{
|
||||
Name: "a",
|
||||
Path: "a",
|
||||
},
|
||||
},
|
||||
expected: &Node[models.CommitFile]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.CommitFile]{
|
||||
{
|
||||
File: &models.CommitFile{Name: "a"},
|
||||
Path: "a",
|
||||
File: &models.CommitFile{Path: "a"},
|
||||
path: "./a",
|
||||
},
|
||||
{
|
||||
File: &models.CommitFile{Name: "b"},
|
||||
Path: "b",
|
||||
File: &models.CommitFile{Path: "b"},
|
||||
path: "./b",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -27,7 +27,7 @@ type CommitFileTree struct {
|
||||
|
||||
func (self *CommitFileTree) CollapseAll() {
|
||||
dirPaths := lo.FilterMap(self.GetAllItems(), func(file *CommitFileNode, index int) (string, bool) {
|
||||
return file.Path, !file.IsFile()
|
||||
return file.path, !file.IsFile()
|
||||
})
|
||||
|
||||
for _, path := range dirPaths {
|
||||
@ -119,7 +119,7 @@ func (self *CommitFileTree) CollapsedPaths() *CollapsedPaths {
|
||||
|
||||
func (self *CommitFileTree) GetFile(path string) *models.CommitFile {
|
||||
for _, file := range self.getFiles() {
|
||||
if file.Name == path {
|
||||
if file.Path == path {
|
||||
return file
|
||||
}
|
||||
}
|
||||
|
@ -148,12 +148,12 @@ func (self *CommitFileTreeViewModel) ToggleShowTree() {
|
||||
if selectedNode == nil {
|
||||
return
|
||||
}
|
||||
path := selectedNode.Path
|
||||
path := selectedNode.path
|
||||
|
||||
if self.InTreeMode() {
|
||||
self.ExpandToPath(path)
|
||||
} else if len(selectedNode.Children) > 0 {
|
||||
path = selectedNode.GetLeaves()[0].Path
|
||||
path = selectedNode.GetLeaves()[0].path
|
||||
}
|
||||
|
||||
index, found := self.GetIndexForPath(path)
|
||||
@ -170,7 +170,7 @@ func (self *CommitFileTreeViewModel) CollapseAll() {
|
||||
return
|
||||
}
|
||||
|
||||
topLevelPath := strings.Split(selectedNode.Path, "/")[0]
|
||||
topLevelPath := strings.Split(selectedNode.path, "/")[0]
|
||||
index, found := self.GetIndexForPath(topLevelPath)
|
||||
if found {
|
||||
self.SetSelectedLineIdx(index)
|
||||
@ -186,7 +186,7 @@ func (self *CommitFileTreeViewModel) ExpandAll() {
|
||||
return
|
||||
}
|
||||
|
||||
index, found := self.GetIndexForPath(selectedNode.Path)
|
||||
index, found := self.GetIndexForPath(selectedNode.path)
|
||||
if found {
|
||||
self.SetSelectedLineIdx(index)
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ func (self *FileNode) GetHasInlineMergeConflicts() bool {
|
||||
if !file.HasInlineMergeConflicts {
|
||||
return false
|
||||
}
|
||||
hasConflicts, _ := mergeconflicts.FileHasConflictMarkers(file.Name)
|
||||
hasConflicts, _ := mergeconflicts.FileHasConflictMarkers(file.Path)
|
||||
return hasConflicts
|
||||
})
|
||||
}
|
||||
@ -69,5 +69,5 @@ func (self *FileNode) GetPreviousPath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
return self.File.PreviousName
|
||||
return self.File.PreviousPath
|
||||
}
|
||||
|
@ -21,103 +21,103 @@ func TestCompress(t *testing.T) {
|
||||
{
|
||||
name: "leaf node",
|
||||
root: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{File: &models.File{Name: "test", ShortStatus: " M", HasStagedChanges: true}, Path: "test"},
|
||||
{File: &models.File{Path: "test", ShortStatus: " M", HasStagedChanges: true}, path: "test"},
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{File: &models.File{Name: "test", ShortStatus: " M", HasStagedChanges: true}, Path: "test"},
|
||||
{File: &models.File{Path: "test", ShortStatus: " M", HasStagedChanges: true}, path: "test"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "big example",
|
||||
root: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
Path: "dir1",
|
||||
path: "dir1",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "file2", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
Path: "dir1/file2",
|
||||
File: &models.File{Path: "file2", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
path: "dir1/file2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "dir2",
|
||||
path: "dir2",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "file3", ShortStatus: " M", HasStagedChanges: true},
|
||||
Path: "dir2/file3",
|
||||
File: &models.File{Path: "file3", ShortStatus: " M", HasStagedChanges: true},
|
||||
path: "dir2/file3",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
Path: "dir2/file4",
|
||||
File: &models.File{Path: "file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
path: "dir2/file4",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "dir3",
|
||||
path: "dir3",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
Path: "dir3/dir3-1",
|
||||
path: "dir3/dir3-1",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
Path: "dir3/dir3-1/file5",
|
||||
File: &models.File{Path: "file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
path: "dir3/dir3-1/file5",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
Path: "file1",
|
||||
File: &models.File{Path: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
path: "file1",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &Node[models.File]{
|
||||
Path: "",
|
||||
path: "",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
Path: "dir1",
|
||||
path: "dir1",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "file2", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
Path: "dir1/file2",
|
||||
File: &models.File{Path: "file2", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
path: "dir1/file2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "dir2",
|
||||
path: "dir2",
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "file3", ShortStatus: " M", HasStagedChanges: true},
|
||||
Path: "dir2/file3",
|
||||
File: &models.File{Path: "file3", ShortStatus: " M", HasStagedChanges: true},
|
||||
path: "dir2/file3",
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
Path: "dir2/file4",
|
||||
File: &models.File{Path: "file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
path: "dir2/file4",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "dir3/dir3-1",
|
||||
path: "dir3/dir3-1",
|
||||
CompressionLevel: 1,
|
||||
Children: []*Node[models.File]{
|
||||
{
|
||||
File: &models.File{Name: "file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
Path: "dir3/dir3-1/file5",
|
||||
File: &models.File{Path: "file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
path: "dir3/dir3-1/file5",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
File: &models.File{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
Path: "file1",
|
||||
File: &models.File{Path: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
path: "file1",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -141,13 +141,13 @@ func TestGetFile(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "valid case",
|
||||
viewModel: NewFileTree(func() []*models.File { return []*models.File{{Name: "blah/one"}, {Name: "blah/two"}} }, nil, false),
|
||||
viewModel: NewFileTree(func() []*models.File { return []*models.File{{Path: "blah/one"}, {Path: "blah/two"}} }, nil, false),
|
||||
path: "blah/two",
|
||||
expected: &models.File{Name: "blah/two"},
|
||||
expected: &models.File{Path: "blah/two"},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
viewModel: NewFileTree(func() []*models.File { return []*models.File{{Name: "blah/one"}, {Name: "blah/two"}} }, nil, false),
|
||||
viewModel: NewFileTree(func() []*models.File { return []*models.File{{Path: "blah/one"}, {Path: "blah/two"}} }, nil, false),
|
||||
path: "blah/three",
|
||||
expected: nil,
|
||||
},
|
||||
|
@ -125,7 +125,7 @@ func (self *FileTree) Get(index int) *FileNode {
|
||||
|
||||
func (self *FileTree) GetFile(path string) *models.File {
|
||||
for _, file := range self.getFiles() {
|
||||
if file.Name == path {
|
||||
if file.Path == path {
|
||||
return file
|
||||
}
|
||||
}
|
||||
@ -185,7 +185,7 @@ func (self *FileTree) ToggleCollapsed(path string) {
|
||||
|
||||
func (self *FileTree) CollapseAll() {
|
||||
dirPaths := lo.FilterMap(self.GetAllItems(), func(file *FileNode, index int) (string, bool) {
|
||||
return file.Path, !file.IsFile()
|
||||
return file.path, !file.IsFile()
|
||||
})
|
||||
|
||||
for _, path := range dirPaths {
|
||||
|
@ -18,67 +18,67 @@ func TestFilterAction(t *testing.T) {
|
||||
name: "filter files with unstaged changes",
|
||||
filter: DisplayUnstaged,
|
||||
files: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "dir2/file5", ShortStatus: "M ", HasStagedChanges: true},
|
||||
{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/file5", ShortStatus: "M ", HasStagedChanges: true},
|
||||
{Path: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
},
|
||||
expected: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter files with staged changes",
|
||||
filter: DisplayStaged,
|
||||
files: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", HasStagedChanges: true},
|
||||
{Name: "dir2/file5", ShortStatus: "M ", HasStagedChanges: false},
|
||||
{Name: "file1", ShortStatus: "M ", HasStagedChanges: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", HasStagedChanges: true},
|
||||
{Path: "dir2/file5", ShortStatus: "M ", HasStagedChanges: false},
|
||||
{Path: "file1", ShortStatus: "M ", HasStagedChanges: true},
|
||||
},
|
||||
expected: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", HasStagedChanges: true},
|
||||
{Name: "file1", ShortStatus: "M ", HasStagedChanges: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", HasStagedChanges: true},
|
||||
{Path: "file1", ShortStatus: "M ", HasStagedChanges: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter files that are tracked",
|
||||
filter: DisplayTracked,
|
||||
files: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", Tracked: true},
|
||||
{Name: "dir2/file5", ShortStatus: "M ", Tracked: false},
|
||||
{Name: "file1", ShortStatus: "M ", Tracked: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", Tracked: true},
|
||||
{Path: "dir2/file5", ShortStatus: "M ", Tracked: false},
|
||||
{Path: "file1", ShortStatus: "M ", Tracked: true},
|
||||
},
|
||||
expected: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", Tracked: true},
|
||||
{Name: "file1", ShortStatus: "M ", Tracked: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", Tracked: true},
|
||||
{Path: "file1", ShortStatus: "M ", Tracked: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter all files",
|
||||
filter: DisplayAll,
|
||||
files: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "dir2/file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
},
|
||||
expected: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "dir2/file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter conflicted files",
|
||||
filter: DisplayConflicted,
|
||||
files: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "DU", HasMergeConflicts: true},
|
||||
{Name: "dir2/file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "dir2/file6", ShortStatus: " M", HasStagedChanges: true},
|
||||
{Name: "file1", ShortStatus: "UU", HasMergeConflicts: true, HasInlineMergeConflicts: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "DU", HasMergeConflicts: true},
|
||||
{Path: "dir2/file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/file6", ShortStatus: " M", HasStagedChanges: true},
|
||||
{Path: "file1", ShortStatus: "UU", HasMergeConflicts: true, HasInlineMergeConflicts: true},
|
||||
},
|
||||
expected: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "DU", HasMergeConflicts: true},
|
||||
{Name: "file1", ShortStatus: "UU", HasMergeConflicts: true, HasInlineMergeConflicts: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "DU", HasMergeConflicts: true},
|
||||
{Path: "file1", ShortStatus: "UU", HasMergeConflicts: true, HasInlineMergeConflicts: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ func (self *FileTreeViewModel) SetTree() {
|
||||
|
||||
// for when you stage the old file of a rename and the new file is in a collapsed dir
|
||||
for _, file := range newFiles {
|
||||
if selectedNode != nil && selectedNode.Path != "" && file.PreviousName == selectedNode.Path {
|
||||
self.ExpandToPath(file.Name)
|
||||
if selectedNode != nil && selectedNode.path != "" && file.PreviousPath == selectedNode.path {
|
||||
self.ExpandToPath(file.Path)
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ func (self *FileTreeViewModel) findNewSelectedIdx(prevNodes []*FileNode, currNod
|
||||
if node.File != nil && node.File.IsRename() {
|
||||
return node.File.Names()
|
||||
} else {
|
||||
return []string{node.Path}
|
||||
return []string{node.path}
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ func (self *FileTreeViewModel) findNewSelectedIdx(prevNodes []*FileNode, currNod
|
||||
|
||||
// If you started off with a rename selected, and now it's broken in two, we want you to jump to the new file, not the old file.
|
||||
// This is because the new should be in the same position as the rename was meaning less cursor jumping
|
||||
foundOldFileInRename := prevNode.File != nil && prevNode.File.IsRename() && node.Path == prevNode.File.PreviousName
|
||||
foundOldFileInRename := prevNode.File != nil && prevNode.File.IsRename() && node.path == prevNode.File.PreviousPath
|
||||
foundNode := utils.StringArraysOverlap(paths, selectedPaths) && !foundOldFileInRename
|
||||
if foundNode {
|
||||
return idx
|
||||
@ -178,12 +178,12 @@ func (self *FileTreeViewModel) ToggleShowTree() {
|
||||
if selectedNode == nil {
|
||||
return
|
||||
}
|
||||
path := selectedNode.Path
|
||||
path := selectedNode.path
|
||||
|
||||
if self.InTreeMode() {
|
||||
self.ExpandToPath(path)
|
||||
} else if len(selectedNode.Children) > 0 {
|
||||
path = selectedNode.GetLeaves()[0].Path
|
||||
path = selectedNode.GetLeaves()[0].path
|
||||
}
|
||||
|
||||
index, found := self.GetIndexForPath(path)
|
||||
@ -200,7 +200,7 @@ func (self *FileTreeViewModel) CollapseAll() {
|
||||
return
|
||||
}
|
||||
|
||||
topLevelPath := strings.Split(selectedNode.Path, "/")[0]
|
||||
topLevelPath := strings.Split(selectedNode.path, "/")[0]
|
||||
index, found := self.GetIndexForPath(topLevelPath)
|
||||
if found {
|
||||
self.SetSelectedLineIdx(index)
|
||||
@ -216,7 +216,7 @@ func (self *FileTreeViewModel) ExpandAll() {
|
||||
return
|
||||
}
|
||||
|
||||
index, found := self.GetIndexForPath(selectedNode.Path)
|
||||
index, found := self.GetIndexForPath(selectedNode.path)
|
||||
if found {
|
||||
self.SetSelectedLineIdx(index)
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ type Node[T any] struct {
|
||||
Children []*Node[T]
|
||||
|
||||
// path of the file/directory
|
||||
Path string
|
||||
// private; use either GetPath() or GetInternalPath() to access
|
||||
path string
|
||||
|
||||
// rather than render a tree as:
|
||||
// a/
|
||||
@ -46,8 +47,20 @@ func (self *Node[T]) GetFile() *T {
|
||||
return self.File
|
||||
}
|
||||
|
||||
// This returns the logical path from the user's point of view. It is the
|
||||
// relative path from the root of the repository.
|
||||
// Use this for display, or when you want to perform some action on the path
|
||||
// (e.g. a git command).
|
||||
func (self *Node[T]) GetPath() string {
|
||||
return self.Path
|
||||
return strings.TrimPrefix(self.path, "./")
|
||||
}
|
||||
|
||||
// This returns the internal path from the tree's point of view. It's the same
|
||||
// as GetPath(), but prefixed with "./" for the root item.
|
||||
// Use this when interacting with the tree itself, e.g. when calling
|
||||
// ToggleCollapsed.
|
||||
func (self *Node[T]) GetInternalPath() string {
|
||||
return self.path
|
||||
}
|
||||
|
||||
func (self *Node[T]) Sort() {
|
||||
@ -89,7 +102,7 @@ func (self *Node[T]) SortChildren() {
|
||||
return 1
|
||||
}
|
||||
|
||||
return strings.Compare(a.GetPath(), b.GetPath())
|
||||
return strings.Compare(a.path, b.path)
|
||||
})
|
||||
|
||||
// TODO: think about making this in-place
|
||||
@ -159,7 +172,7 @@ func (self *Node[T]) EveryFile(test func(*T) bool) bool {
|
||||
func (self *Node[T]) Flatten(collapsedPaths *CollapsedPaths) []*Node[T] {
|
||||
result := []*Node[T]{self}
|
||||
|
||||
if len(self.Children) > 0 && !collapsedPaths.IsCollapsed(self.GetPath()) {
|
||||
if len(self.Children) > 0 && !collapsedPaths.IsCollapsed(self.path) {
|
||||
result = append(result, lo.FlatMap(self.Children, func(child *Node[T], _ int) []*Node[T] {
|
||||
return child.Flatten(collapsedPaths)
|
||||
})...)
|
||||
@ -185,7 +198,7 @@ func (self *Node[T]) getNodeAtIndexAux(index int, collapsedPaths *CollapsedPaths
|
||||
return self, offset
|
||||
}
|
||||
|
||||
if !collapsedPaths.IsCollapsed(self.GetPath()) {
|
||||
if !collapsedPaths.IsCollapsed(self.path) {
|
||||
for _, child := range self.Children {
|
||||
foundNode, offsetChange := child.getNodeAtIndexAux(index-offset, collapsedPaths)
|
||||
offset += offsetChange
|
||||
@ -201,11 +214,11 @@ func (self *Node[T]) getNodeAtIndexAux(index int, collapsedPaths *CollapsedPaths
|
||||
func (self *Node[T]) GetIndexForPath(path string, collapsedPaths *CollapsedPaths) (int, bool) {
|
||||
offset := 0
|
||||
|
||||
if self.GetPath() == path {
|
||||
if self.path == path {
|
||||
return offset, true
|
||||
}
|
||||
|
||||
if !collapsedPaths.IsCollapsed(self.GetPath()) {
|
||||
if !collapsedPaths.IsCollapsed(self.path) {
|
||||
for _, child := range self.Children {
|
||||
offsetChange, found := child.GetIndexForPath(path, collapsedPaths)
|
||||
offset += offsetChange + 1
|
||||
@ -225,7 +238,7 @@ func (self *Node[T]) Size(collapsedPaths *CollapsedPaths) int {
|
||||
|
||||
output := 1
|
||||
|
||||
if !collapsedPaths.IsCollapsed(self.GetPath()) {
|
||||
if !collapsedPaths.IsCollapsed(self.path) {
|
||||
for _, child := range self.Children {
|
||||
output += child.Size(collapsedPaths)
|
||||
}
|
||||
@ -309,5 +322,5 @@ func (self *Node[T]) Description() string {
|
||||
}
|
||||
|
||||
func (self *Node[T]) Name() string {
|
||||
return path.Base(self.Path)
|
||||
return path.Base(self.path)
|
||||
}
|
||||
|
@ -52,11 +52,11 @@ func commitFilePatchStatus(node *filetree.Node[models.CommitFile], tree *filetre
|
||||
// be whatever status it is, but if it's a non-leaf it will determine its status
|
||||
// based on the leaves of that subtree
|
||||
if node.EveryFile(func(file *models.CommitFile) bool {
|
||||
return patchBuilder.GetFileStatus(file.Name, tree.GetRef().RefName()) == patch.WHOLE
|
||||
return patchBuilder.GetFileStatus(file.Path, tree.GetRef().RefName()) == patch.WHOLE
|
||||
}) {
|
||||
return patch.WHOLE
|
||||
} else if node.EveryFile(func(file *models.CommitFile) bool {
|
||||
return patchBuilder.GetFileStatus(file.Name, tree.GetRef().RefName()) == patch.UNSELECTED
|
||||
return patchBuilder.GetFileStatus(file.Path, tree.GetRef().RefName()) == patch.UNSELECTED
|
||||
}) {
|
||||
return patch.UNSELECTED
|
||||
} else {
|
||||
@ -91,11 +91,11 @@ func renderAux[T any](
|
||||
|
||||
arr := []string{}
|
||||
if !isRoot {
|
||||
isCollapsed := collapsedPaths.IsCollapsed(node.GetPath())
|
||||
isCollapsed := collapsedPaths.IsCollapsed(node.GetInternalPath())
|
||||
arr = append(arr, renderLine(node, treeDepth, visualDepth, isCollapsed))
|
||||
}
|
||||
|
||||
if collapsedPaths.IsCollapsed(node.GetPath()) {
|
||||
if collapsedPaths.IsCollapsed(node.GetInternalPath()) {
|
||||
return arr
|
||||
}
|
||||
|
||||
@ -293,13 +293,19 @@ func getColorForChangeStatus(changeStatus string) style.TextStyle {
|
||||
}
|
||||
|
||||
func fileNameAtDepth(node *filetree.Node[models.File], depth int) string {
|
||||
splitName := split(node.Path)
|
||||
splitName := split(node.GetInternalPath())
|
||||
if depth == 0 && splitName[0] == "." {
|
||||
if len(splitName) == 1 {
|
||||
return "/"
|
||||
}
|
||||
depth = 1
|
||||
}
|
||||
name := join(splitName[depth:])
|
||||
|
||||
if node.File != nil && node.File.IsRename() {
|
||||
splitPrevName := split(node.File.PreviousName)
|
||||
splitPrevName := split(node.File.PreviousPath)
|
||||
|
||||
prevName := node.File.PreviousName
|
||||
prevName := node.File.PreviousPath
|
||||
// if the file has just been renamed inside the same directory, we can shave off
|
||||
// the prefix for the previous path too. Otherwise we'll keep it unchanged
|
||||
sameParentDir := len(splitName) == len(splitPrevName) && join(splitName[0:depth]) == join(splitPrevName[0:depth])
|
||||
@ -314,7 +320,13 @@ func fileNameAtDepth(node *filetree.Node[models.File], depth int) string {
|
||||
}
|
||||
|
||||
func commitFileNameAtDepth(node *filetree.Node[models.CommitFile], depth int) string {
|
||||
splitName := split(node.Path)
|
||||
splitName := split(node.GetInternalPath())
|
||||
if depth == 0 && splitName[0] == "." {
|
||||
if len(splitName) == 1 {
|
||||
return "/"
|
||||
}
|
||||
depth = 1
|
||||
}
|
||||
name := join(splitName[depth:])
|
||||
|
||||
return name
|
||||
|
@ -34,48 +34,50 @@ func TestRenderFileTree(t *testing.T) {
|
||||
{
|
||||
name: "leaf node",
|
||||
files: []*models.File{
|
||||
{Name: "test", ShortStatus: " M", HasStagedChanges: true},
|
||||
{Path: "test", ShortStatus: " M", HasStagedChanges: true},
|
||||
},
|
||||
expected: []string{" M test"},
|
||||
},
|
||||
{
|
||||
name: "numstat",
|
||||
files: []*models.File{
|
||||
{Name: "test", ShortStatus: " M", HasStagedChanges: true, LinesAdded: 1, LinesDeleted: 1},
|
||||
{Name: "test2", ShortStatus: " M", HasStagedChanges: true, LinesAdded: 1},
|
||||
{Name: "test3", ShortStatus: " M", HasStagedChanges: true, LinesDeleted: 1},
|
||||
{Name: "test4", ShortStatus: " M", HasStagedChanges: true, LinesAdded: 0, LinesDeleted: 0},
|
||||
{Path: "test", ShortStatus: " M", HasStagedChanges: true, LinesAdded: 1, LinesDeleted: 1},
|
||||
{Path: "test2", ShortStatus: " M", HasStagedChanges: true, LinesAdded: 1},
|
||||
{Path: "test3", ShortStatus: " M", HasStagedChanges: true, LinesDeleted: 1},
|
||||
{Path: "test4", ShortStatus: " M", HasStagedChanges: true, LinesAdded: 0, LinesDeleted: 0},
|
||||
},
|
||||
showLineChanges: true,
|
||||
expected: []string{
|
||||
" M test +1 -1",
|
||||
" M test2 +1",
|
||||
" M test3 -1",
|
||||
" M test4",
|
||||
"▼ /",
|
||||
" M test +1 -1",
|
||||
" M test2 +1",
|
||||
" M test3 -1",
|
||||
" M test4",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "big example",
|
||||
files: []*models.File{
|
||||
{Name: "dir1/file2", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "dir1/file3", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "dir2/dir2/file3", ShortStatus: " M", HasStagedChanges: true},
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "dir2/file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir1/file2", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir1/file3", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/dir2/file3", ShortStatus: " M", HasStagedChanges: true},
|
||||
{Path: "dir2/dir2/file4", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "dir2/file5", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
{Path: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
|
||||
},
|
||||
expected: toStringSlice(
|
||||
`
|
||||
▶ dir1
|
||||
▼ dir2
|
||||
▼ /
|
||||
▶ dir1
|
||||
▼ dir2
|
||||
M file3
|
||||
M file4
|
||||
M file5
|
||||
M file1
|
||||
▼ dir2
|
||||
M file3
|
||||
M file4
|
||||
M file5
|
||||
M file1
|
||||
`,
|
||||
),
|
||||
collapsedPaths: []string{"dir1"},
|
||||
collapsedPaths: []string{"./dir1"},
|
||||
},
|
||||
}
|
||||
|
||||
@ -111,32 +113,33 @@ func TestRenderCommitFileTree(t *testing.T) {
|
||||
{
|
||||
name: "leaf node",
|
||||
files: []*models.CommitFile{
|
||||
{Name: "test", ChangeStatus: "A"},
|
||||
{Path: "test", ChangeStatus: "A"},
|
||||
},
|
||||
expected: []string{"A test"},
|
||||
},
|
||||
{
|
||||
name: "big example",
|
||||
files: []*models.CommitFile{
|
||||
{Name: "dir1/file2", ChangeStatus: "M"},
|
||||
{Name: "dir1/file3", ChangeStatus: "A"},
|
||||
{Name: "dir2/dir2/file3", ChangeStatus: "D"},
|
||||
{Name: "dir2/dir2/file4", ChangeStatus: "M"},
|
||||
{Name: "dir2/file5", ChangeStatus: "M"},
|
||||
{Name: "file1", ChangeStatus: "M"},
|
||||
{Path: "dir1/file2", ChangeStatus: "M"},
|
||||
{Path: "dir1/file3", ChangeStatus: "A"},
|
||||
{Path: "dir2/dir2/file3", ChangeStatus: "D"},
|
||||
{Path: "dir2/dir2/file4", ChangeStatus: "M"},
|
||||
{Path: "dir2/file5", ChangeStatus: "M"},
|
||||
{Path: "file1", ChangeStatus: "M"},
|
||||
},
|
||||
expected: toStringSlice(
|
||||
`
|
||||
▶ dir1
|
||||
▼ dir2
|
||||
▼ /
|
||||
▶ dir1
|
||||
▼ dir2
|
||||
D file3
|
||||
M file4
|
||||
M file5
|
||||
M file1
|
||||
▼ dir2
|
||||
D file3
|
||||
M file4
|
||||
M file5
|
||||
M file1
|
||||
`,
|
||||
),
|
||||
collapsedPaths: []string{"dir1"},
|
||||
collapsedPaths: []string{"./dir1"},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,8 @@ func fileShimFromModelFile(file *models.File) *File {
|
||||
}
|
||||
|
||||
return &File{
|
||||
Name: file.Name,
|
||||
PreviousName: file.PreviousName,
|
||||
Name: file.Path,
|
||||
PreviousName: file.PreviousPath,
|
||||
HasStagedChanges: file.HasStagedChanges,
|
||||
HasUnstagedChanges: file.HasUnstagedChanges,
|
||||
Tracked: file.Tracked,
|
||||
@ -141,7 +141,7 @@ func commitFileShimFromModelRemote(commitFile *models.CommitFile) *CommitFile {
|
||||
}
|
||||
|
||||
return &CommitFile{
|
||||
Name: commitFile.Name,
|
||||
Name: commitFile.Path,
|
||||
ChangeStatus: commitFile.ChangeStatus,
|
||||
}
|
||||
}
|
||||
|
@ -72,8 +72,9 @@ var ResetToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("hard commit"),
|
||||
)
|
||||
t.Views().Files().Lines(
|
||||
Contains("file-1").Contains("A"),
|
||||
Contains("file-2").Contains("A"),
|
||||
Equals("▼ /"),
|
||||
Equals(" A file-1"),
|
||||
Equals(" A file-2"),
|
||||
)
|
||||
|
||||
// hard reset
|
||||
|
@ -21,19 +21,23 @@ var Commit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("?? myfile").IsSelected(),
|
||||
Contains("?? myfile2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ?? myfile"),
|
||||
Equals(" ?? myfile2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction(). // stage file
|
||||
Lines(
|
||||
Contains("A myfile").IsSelected(),
|
||||
Contains("?? myfile2"),
|
||||
Equals("▼ /"),
|
||||
Equals(" A myfile").IsSelected(),
|
||||
Equals(" ?? myfile2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction(). // stage other file
|
||||
Lines(
|
||||
Contains("A myfile"),
|
||||
Contains("A myfile2").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" A myfile"),
|
||||
Equals(" A myfile2").IsSelected(),
|
||||
).
|
||||
Press(keys.Files.CommitChanges)
|
||||
|
||||
@ -54,8 +58,9 @@ var Commit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("A myfile"),
|
||||
Contains("A myfile2"),
|
||||
Equals("▼ /"),
|
||||
Equals(" A myfile"),
|
||||
Equals(" A myfile2"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -25,6 +25,12 @@ var CommitSwitchToEditor = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ?? file1"),
|
||||
Equals(" ?? file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction(). // stage one of the files
|
||||
Press(keys.Files.CommitChanges)
|
||||
|
||||
@ -45,6 +51,9 @@ var CommitSwitchToEditor = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// Now check that the preserved commit message was cleared:
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Lines(
|
||||
Equals("?? file2"),
|
||||
).
|
||||
PressPrimaryAction(). // stage the other file
|
||||
Press(keys.Files.CommitChanges)
|
||||
|
||||
|
@ -43,13 +43,14 @@ var DiscardOldFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir1").IsSelected(),
|
||||
Contains("subd1"),
|
||||
Contains("subfile0"),
|
||||
Contains("d1_file0"),
|
||||
Contains("dir2"),
|
||||
Contains("d2_file1"),
|
||||
Contains("d2_file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ▼ subd1"),
|
||||
Equals(" A subfile0"),
|
||||
Equals(" A d1_file0"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" A d2_file1"),
|
||||
Equals(" A d2_file2"),
|
||||
).
|
||||
NavigateToLine(Contains("d1_file0")).
|
||||
Press(keys.Universal.Remove)
|
||||
@ -62,11 +63,12 @@ var DiscardOldFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir1/subd1"),
|
||||
Contains("subfile0"),
|
||||
Contains("dir2"),
|
||||
Contains("d2_file1").IsSelected(),
|
||||
Contains("d2_file2"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1/subd1"),
|
||||
Equals(" A subfile0"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" A d2_file1").IsSelected(),
|
||||
Equals(" A d2_file2"),
|
||||
).
|
||||
PressEscape()
|
||||
|
||||
@ -84,11 +86,11 @@ var DiscardOldFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir2").IsSelected(),
|
||||
Contains("d2_file1"),
|
||||
Contains("d2_file2"),
|
||||
Contains("d2_file3"),
|
||||
Contains("d2_file4"),
|
||||
Equals("▼ dir2").IsSelected(),
|
||||
Equals(" M d2_file1"),
|
||||
Equals(" D d2_file2"),
|
||||
Equals(" A d2_file3"),
|
||||
Equals(" A d2_file4"),
|
||||
).
|
||||
NavigateToLine(Contains("d2_file1")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
@ -122,11 +124,11 @@ var DiscardOldFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir1").IsSelected(),
|
||||
Contains("subd1"),
|
||||
Contains("file2ToRemove"),
|
||||
Contains("fileToRemove"),
|
||||
Contains("multiLineFile"),
|
||||
Equals("▼ dir1").IsSelected(),
|
||||
Equals(" ▼ subd1"),
|
||||
Equals(" A file2ToRemove"),
|
||||
Equals(" A fileToRemove"),
|
||||
Equals(" A multiLineFile"),
|
||||
).
|
||||
NavigateToLine(Contains("multiLineFile")).
|
||||
PressEnter()
|
||||
@ -142,11 +144,11 @@ var DiscardOldFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir1"),
|
||||
Contains("subd1"),
|
||||
Contains("file2ToRemove"),
|
||||
Contains("fileToRemove"),
|
||||
Contains("multiLineFile").IsSelected(),
|
||||
Equals("▼ dir1"),
|
||||
Equals(" ▼ subd1"),
|
||||
Equals(" A file2ToRemove"),
|
||||
Equals(" A fileToRemove"),
|
||||
Equals(" ◐ multiLineFile").IsSelected(),
|
||||
).
|
||||
NavigateToLine(Contains("dir1")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
|
@ -20,6 +20,12 @@ var Reword = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("myfile"),
|
||||
Contains("myfile2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction().
|
||||
Press(keys.Files.CommitChanges)
|
||||
|
||||
|
@ -21,7 +21,12 @@ var Staged = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
SelectedLine(Contains("myfile")).
|
||||
Lines(
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("myfile"),
|
||||
Contains("myfile2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction(). // stage the file
|
||||
PressEnter()
|
||||
|
||||
|
@ -22,7 +22,12 @@ var StagedWithoutHooks = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// stage the file
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
SelectedLine(Contains("myfile")).
|
||||
Lines(
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("myfile"),
|
||||
Contains("myfile2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction().
|
||||
PressEnter()
|
||||
|
||||
|
@ -21,7 +21,12 @@ var Unstaged = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
SelectedLine(Contains("myfile")).
|
||||
Lines(
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("myfile"),
|
||||
Contains("myfile2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressEnter()
|
||||
|
||||
t.Views().Staging().
|
||||
|
@ -18,8 +18,9 @@ var Filter = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("UU").Contains("file1").IsSelected(),
|
||||
Contains("UU").Contains("file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" UU file1"),
|
||||
Equals(" UU file2"),
|
||||
).
|
||||
Press(keys.Files.OpenStatusFilter).
|
||||
Tap(func() {
|
||||
@ -29,10 +30,11 @@ var Filter = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("UU").Contains("file1").IsSelected(),
|
||||
Contains("UU").Contains("file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" UU file1"),
|
||||
Equals(" UU file2"),
|
||||
// now we see the non-merge conflict file
|
||||
Contains("A ").Contains("file3"),
|
||||
Equals(" A file3"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -18,9 +18,11 @@ var ResolveMultipleFiles = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("UU").Contains("file1").IsSelected(),
|
||||
Contains("UU").Contains("file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" UU file1"),
|
||||
Equals(" UU file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressEnter()
|
||||
|
||||
t.Views().MergeConflicts().
|
||||
@ -35,7 +37,7 @@ var ResolveMultipleFiles = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("UU").Contains("file2").IsSelected(),
|
||||
Equals("UU file2").IsSelected(),
|
||||
).
|
||||
PressEnter()
|
||||
|
||||
|
@ -20,9 +20,11 @@ var ResolveNoAutoStage = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("UU").Contains("file1").IsSelected(),
|
||||
Contains("UU").Contains("file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" UU file1"),
|
||||
Equals(" UU file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressEnter()
|
||||
|
||||
t.Views().MergeConflicts().
|
||||
@ -38,13 +40,14 @@ var ResolveNoAutoStage = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
IsFocused().
|
||||
// Resolving the conflict didn't auto-stage it
|
||||
Lines(
|
||||
Contains("UU").Contains("file1").IsSelected(),
|
||||
Contains("UU").Contains("file2"),
|
||||
Equals("▼ /"),
|
||||
Equals(" UU file1").IsSelected(),
|
||||
Equals(" UU file2"),
|
||||
).
|
||||
// So do that manually
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("UU").Contains("file2").IsSelected(),
|
||||
Equals("UU file2").IsSelected(),
|
||||
).
|
||||
// Trying to stage a file that still has conflicts is not allowed:
|
||||
PressPrimaryAction().
|
||||
@ -70,12 +73,12 @@ var ResolveNoAutoStage = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
IsFocused().
|
||||
// Again, resolving the conflict didn't auto-stage it
|
||||
Lines(
|
||||
Contains("UU").Contains("file2").IsSelected(),
|
||||
Equals("UU file2").IsSelected(),
|
||||
).
|
||||
// Doing that manually now works:
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("A").Contains("file3").IsSelected(),
|
||||
Equals("A file3").IsSelected(),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -68,6 +68,7 @@ var CustomCommandsSubmenu = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Equals("▼ /"),
|
||||
Contains("myfile-commits"),
|
||||
Contains("myfile-files"),
|
||||
)
|
||||
|
@ -21,26 +21,27 @@ var CollapseExpand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains("??").Contains("file-one"),
|
||||
Contains("dir2"),
|
||||
Contains("??").Contains("file-two"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir"),
|
||||
Equals(" ?? file-one"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" ?? file-two"),
|
||||
)
|
||||
|
||||
t.Views().Files().
|
||||
Press(keys.Files.CollapseAll).
|
||||
Lines(
|
||||
Contains("dir"),
|
||||
Contains("dir2"),
|
||||
Equals("▶ /"),
|
||||
)
|
||||
|
||||
t.Views().Files().
|
||||
Press(keys.Files.ExpandAll).
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains("??").Contains("file-one"),
|
||||
Contains("dir2"),
|
||||
Contains("??").Contains("file-two"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir"),
|
||||
Equals(" ?? file-one"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" ?? file-two"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -29,33 +29,35 @@ var DiscardRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("▼ dir1").IsSelected(),
|
||||
Contains(" ??").Contains("file-1a"),
|
||||
Contains(" ??").Contains("file-1b"),
|
||||
Contains("▼ dir2"),
|
||||
Contains(" ??").Contains("file-2a"),
|
||||
Contains(" M").Contains("file-2b"),
|
||||
Contains("▼ dir3"),
|
||||
Contains(" ??").Contains("file-3a"),
|
||||
Contains(" M").Contains("file-3b"),
|
||||
Contains("??").Contains("file-a"),
|
||||
Contains("??").Contains("file-b"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-1a"),
|
||||
Equals(" ?? file-1b"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" ?? file-2a"),
|
||||
Equals(" M file-2b"),
|
||||
Equals(" ▼ dir3"),
|
||||
Equals(" ?? file-3a"),
|
||||
Equals(" M file-3b"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b"),
|
||||
).
|
||||
NavigateToLine(Contains("file-1b")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("file-2a")).
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-1a"),
|
||||
Contains(" ??").Contains("file-1b").IsSelected(),
|
||||
Contains("▼ dir2").IsSelected(),
|
||||
Contains(" ??").Contains("file-2a").IsSelected(),
|
||||
Contains(" M").Contains("file-2b"),
|
||||
Contains("▼ dir3"),
|
||||
Contains(" ??").Contains("file-3a"),
|
||||
Contains(" M").Contains("file-3b"),
|
||||
Contains("??").Contains("file-a"),
|
||||
Contains("??").Contains("file-b"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-1a"),
|
||||
Equals(" ?? file-1b").IsSelected(),
|
||||
Equals(" ▼ dir2").IsSelected(),
|
||||
Equals(" ?? file-2a").IsSelected(),
|
||||
Equals(" M file-2b"),
|
||||
Equals(" ▼ dir3"),
|
||||
Equals(" ?? file-3a"),
|
||||
Equals(" M file-3b"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b"),
|
||||
).
|
||||
// Discard
|
||||
Press(keys.Universal.Remove).
|
||||
@ -66,24 +68,26 @@ var DiscardRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-1a"),
|
||||
Contains("▼ dir3").IsSelected(),
|
||||
Contains(" ??").Contains("file-3a"),
|
||||
Contains(" M").Contains("file-3b"),
|
||||
Contains("??").Contains("file-a"),
|
||||
Contains("??").Contains("file-b"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-1a"),
|
||||
Equals(" ▼ dir3").IsSelected(),
|
||||
Equals(" ?? file-3a"),
|
||||
Equals(" M file-3b"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b"),
|
||||
).
|
||||
// Verify you can discard collapsed directories in range select
|
||||
PressEnter().
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("file-a")).
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-1a"),
|
||||
Contains("▶ dir3").IsSelected(),
|
||||
Contains("??").Contains("file-a").IsSelected(),
|
||||
Contains("??").Contains("file-b"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-1a"),
|
||||
Equals(" ▶ dir3").IsSelected(),
|
||||
Equals(" ?? file-a").IsSelected(),
|
||||
Equals(" ?? file-b"),
|
||||
).
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
@ -93,9 +97,10 @@ var DiscardRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-1a"),
|
||||
Contains("??").Contains("file-b").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-1a"),
|
||||
Equals(" ?? file-b").IsSelected(),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -24,16 +24,18 @@ var DiscardStagedChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains(` M file2`).IsSelected(),
|
||||
Contains(`?? file3`),
|
||||
Contains(` M fileToRemove`),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" M file2"),
|
||||
Equals(" ?? file3"),
|
||||
Equals(" M fileToRemove"),
|
||||
).
|
||||
NavigateToLine(Contains(`fileToRemove`)).
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains(` M file2`),
|
||||
Contains(`?? file3`),
|
||||
Contains(`M fileToRemove`).IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file2"),
|
||||
Equals(" ?? file3"),
|
||||
Equals(" M fileToRemove").IsSelected(),
|
||||
).
|
||||
Press(keys.Files.ViewResetOptions)
|
||||
|
||||
@ -42,8 +44,9 @@ var DiscardStagedChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// staged file has been removed
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains(` M file2`),
|
||||
Contains(`?? file3`).IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file2"),
|
||||
Equals(" ?? file3").IsSelected(),
|
||||
)
|
||||
|
||||
// the file should have the same content that it originally had, given that that was committed already
|
||||
|
@ -30,13 +30,15 @@ var DiscardUnstagedDirChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains("subdir"),
|
||||
Contains("??").Contains("unstaged-file-one"),
|
||||
Contains("MM").Contains("file-one"),
|
||||
Contains("??").Contains("unstaged-file-two"),
|
||||
Contains("??").Contains("unstaged-file-three"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir"),
|
||||
Equals(" ▼ subdir"),
|
||||
Equals(" ?? unstaged-file-one"),
|
||||
Equals(" MM file-one"),
|
||||
Equals(" ?? unstaged-file-two"),
|
||||
Equals(" ?? unstaged-file-three"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
@ -45,10 +47,11 @@ var DiscardUnstagedDirChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains("M ").Contains("file-one"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir").IsSelected(),
|
||||
Equals(" M file-one"),
|
||||
// this guy remains untouched because it wasn't inside the 'dir' directory
|
||||
Contains("??").Contains("unstaged-file-three"),
|
||||
Equals(" ?? unstaged-file-three"),
|
||||
)
|
||||
|
||||
t.FileSystem().FileContent("dir/file-one", Equals("original content\nnew content\n"))
|
||||
|
@ -26,9 +26,11 @@ var DiscardUnstagedFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("MM").Contains("file-one").IsSelected(),
|
||||
Contains("AM").Contains("file-two"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" MM file-one"),
|
||||
Equals(" AM file-two"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
@ -37,13 +39,15 @@ var DiscardUnstagedFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("M ").Contains("file-one").IsSelected(),
|
||||
Contains("AM").Contains("file-two"),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file-one").IsSelected(),
|
||||
Equals(" AM file-two"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Lines(
|
||||
Contains("M ").Contains("file-one"),
|
||||
Contains("AM").Contains("file-two").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file-one"),
|
||||
Equals(" AM file-two").IsSelected(),
|
||||
).
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
@ -53,8 +57,9 @@ var DiscardUnstagedFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("M ").Contains("file-one"),
|
||||
Contains("A ").Contains("file-two").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file-one"),
|
||||
Equals(" A file-two").IsSelected(),
|
||||
)
|
||||
|
||||
t.FileSystem().FileContent("file-one", Equals("original content\nnew content\n"))
|
||||
|
@ -26,27 +26,29 @@ var DiscardUnstagedRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("▼ dir1").IsSelected(),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains(" ??").Contains("file-b"),
|
||||
Contains("▼ dir2"),
|
||||
Contains(" A ").Contains("file-c"),
|
||||
Contains(" M").Contains("file-d"),
|
||||
Contains("??").Contains("file-e"),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" A file-c"),
|
||||
Equals(" M file-d"),
|
||||
Equals(" ?? file-e"),
|
||||
Equals(" ?? file-f"),
|
||||
).
|
||||
NavigateToLine(Contains("file-b")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("file-c")).
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains(" ??").Contains("file-b").IsSelected(),
|
||||
Contains("▼ dir2").IsSelected(),
|
||||
Contains(" A ").Contains("file-c").IsSelected(),
|
||||
Contains(" M").Contains("file-d"),
|
||||
Contains("??").Contains("file-e"),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b").IsSelected(),
|
||||
Equals(" ▼ dir2").IsSelected(),
|
||||
Equals(" A file-c").IsSelected(),
|
||||
Equals(" M file-d"),
|
||||
Equals(" ?? file-e"),
|
||||
Equals(" ?? file-f"),
|
||||
).
|
||||
// Discard
|
||||
Press(keys.Universal.Remove).
|
||||
@ -60,14 +62,15 @@ var DiscardUnstagedRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// file-c is still there because it contained no unstaged changes
|
||||
// file-d is gone because it was selected via dir2 and contained only unstaged changes
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains("▼ dir2"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ▼ dir2"),
|
||||
// Re-selecting file-c because it's where the selected line index
|
||||
// was before performing the action.
|
||||
Contains(" A ").Contains("file-c").IsSelected(),
|
||||
Contains("??").Contains("file-e"),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals(" A file-c").IsSelected(),
|
||||
Equals(" ?? file-e"),
|
||||
Equals(" ?? file-f"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -21,11 +21,17 @@ var DiscardVariousChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
label string
|
||||
}
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
TopLines(
|
||||
Equals("▼ /").IsSelected(),
|
||||
)
|
||||
|
||||
discardOneByOne := func(files []statusFile) {
|
||||
for _, file := range files {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
SelectedLine(Contains(file.status + " " + file.label)).
|
||||
NavigateToLine(Contains(file.status + " " + file.label)).
|
||||
Press(keys.Universal.Remove)
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
|
@ -19,14 +19,16 @@ var DiscardVariousChangesRangeSelect = NewIntegrationTest(NewIntegrationTestArgs
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("UA").Contains("added-them-changed-us.txt").IsSelected(),
|
||||
Contains("AA").Contains("both-added.txt"),
|
||||
Contains("DD").Contains("both-deleted.txt"),
|
||||
Contains("UU").Contains("both-modded.txt"),
|
||||
Contains("AU").Contains("changed-them-added-us.txt"),
|
||||
Contains("UD").Contains("deleted-them.txt"),
|
||||
Contains("DU").Contains("deleted-us.txt"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" UA added-them-changed-us.txt"),
|
||||
Equals(" AA both-added.txt"),
|
||||
Equals(" DD both-deleted.txt"),
|
||||
Equals(" UU both-modded.txt"),
|
||||
Equals(" AU changed-them-added-us.txt"),
|
||||
Equals(" UD deleted-them.txt"),
|
||||
Equals(" DU deleted-us.txt"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("deleted-us.txt")).
|
||||
Press(keys.Universal.Remove).
|
||||
@ -42,17 +44,18 @@ var DiscardVariousChangesRangeSelect = NewIntegrationTest(NewIntegrationTestArgs
|
||||
Cancel()
|
||||
}).
|
||||
Lines(
|
||||
Contains("AM").Contains("added-changed.txt").IsSelected(),
|
||||
Contains("MD").Contains("change-delete.txt"),
|
||||
Contains("D ").Contains("delete-change.txt"),
|
||||
Contains("D ").Contains("deleted-staged.txt"),
|
||||
Contains(" D").Contains("deleted.txt"),
|
||||
Contains("MM").Contains("double-modded.txt"),
|
||||
Contains("M ").Contains("modded-staged.txt"),
|
||||
Contains(" M").Contains("modded.txt"),
|
||||
Contains("A ").Contains("new-staged.txt"),
|
||||
Contains("??").Contains("new.txt"),
|
||||
Contains("R ").Contains("renamed.txt → renamed2.txt"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" AM added-changed.txt"),
|
||||
Equals(" MD change-delete.txt"),
|
||||
Equals(" D delete-change.txt"),
|
||||
Equals(" D deleted-staged.txt"),
|
||||
Equals(" D deleted.txt"),
|
||||
Equals(" MM double-modded.txt"),
|
||||
Equals(" M modded-staged.txt"),
|
||||
Equals(" M modded.txt"),
|
||||
Equals(" A new-staged.txt"),
|
||||
Equals(" ?? new.txt"),
|
||||
Equals(" R renamed.txt → renamed2.txt"),
|
||||
).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("renamed.txt")).
|
||||
|
@ -20,10 +20,12 @@ var Gitignore = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains(`?? .gitignore`).IsSelected(),
|
||||
Contains(`?? toExclude`),
|
||||
Contains(`?? toIgnore`),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ?? .gitignore"),
|
||||
Equals(" ?? toExclude"),
|
||||
Equals(" ?? toIgnore"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Press(keys.Files.IgnoreFile).
|
||||
// ensure we can't exclude the .gitignore file
|
||||
Tap(func() {
|
||||
|
@ -31,6 +31,7 @@ var RememberCommitMessageAfterFail = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Equals("▼ /"),
|
||||
Contains("bad"),
|
||||
Contains("one"),
|
||||
).
|
||||
@ -40,6 +41,7 @@ var RememberCommitMessageAfterFail = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.ExpectPopup().Alert().Title(Equals("Error")).Content(Contains("Git command failed")).Confirm()
|
||||
}).
|
||||
NavigateToLine(Contains("bad")).
|
||||
Press(keys.Universal.Remove). // remove file that triggers pre-commit hook to fail
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
|
@ -21,15 +21,16 @@ var RenameSimilarityThresholdChange = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("D ").Contains("original"),
|
||||
Contains("A ").Contains("renamed"),
|
||||
Equals("▼ /"),
|
||||
Equals(" D original"),
|
||||
Equals(" A renamed"),
|
||||
).
|
||||
Press(keys.Universal.DecreaseRenameSimilarityThreshold).
|
||||
Tap(func() {
|
||||
t.ExpectToast(Equals("Changed rename similarity threshold to 45%"))
|
||||
}).
|
||||
Lines(
|
||||
Contains("R ").Contains("original → renamed"),
|
||||
Equals("R original → renamed"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -21,12 +21,13 @@ var StageChildrenRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("▼ baz").IsSelected(),
|
||||
Contains(" ??").Contains("file"),
|
||||
Contains("▼ bazbam"),
|
||||
Contains(" ??").Contains("file"),
|
||||
Contains("??").Contains("foo"),
|
||||
Contains("??").Contains("foobar"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ baz"),
|
||||
Equals(" ?? file"),
|
||||
Equals(" ▼ bazbam"),
|
||||
Equals(" ?? file"),
|
||||
Equals(" ?? foo"),
|
||||
Equals(" ?? foobar"),
|
||||
).
|
||||
// Select everything
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
@ -34,12 +35,13 @@ var StageChildrenRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// Stage
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("▼ baz").IsSelected(),
|
||||
Contains(" A ").Contains("file").IsSelected(),
|
||||
Contains("▼ bazbam").IsSelected(),
|
||||
Contains(" A ").Contains("file").IsSelected(),
|
||||
Contains("A ").Contains("foo").IsSelected(),
|
||||
Contains("A ").Contains("foobar").IsSelected(),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ baz").IsSelected(),
|
||||
Equals(" A file").IsSelected(),
|
||||
Equals(" ▼ bazbam").IsSelected(),
|
||||
Equals(" A file").IsSelected(),
|
||||
Equals(" A foo").IsSelected(),
|
||||
Equals(" A foobar").IsSelected(),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -23,28 +23,33 @@ var StageDeletedRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains(" D").Contains("file-a").IsSelected(),
|
||||
Contains(" D").Contains("file-b"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" D file-a"),
|
||||
Equals(" D file-b"),
|
||||
).
|
||||
SelectNextItem().
|
||||
// Stage a single deleted file
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("D ").Contains("file-a").IsSelected(),
|
||||
Contains(" D").Contains("file-b"),
|
||||
Equals("▼ /"),
|
||||
Equals(" D file-a").IsSelected(),
|
||||
Equals(" D file-b"),
|
||||
).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("file-b")).
|
||||
// Stage both files while a deleted file is already staged
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("D ").Contains("file-a").IsSelected(),
|
||||
Contains("D ").Contains("file-b").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" D file-a").IsSelected(),
|
||||
Equals(" D file-b").IsSelected(),
|
||||
).
|
||||
// Unstage; back to everything being unstaged
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains(" D").Contains("file-a").IsSelected(),
|
||||
Contains(" D").Contains("file-b").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" D file-a").IsSelected(),
|
||||
Equals(" D file-b").IsSelected(),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -26,14 +26,15 @@ var StageRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("▼ dir1").IsSelected(),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains(" ??").Contains("file-b"),
|
||||
Contains("▼ dir2"),
|
||||
Contains(" ??").Contains("file-c"),
|
||||
Contains(" M").Contains("file-d"),
|
||||
Contains("??").Contains("file-e"),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" ?? file-c"),
|
||||
Equals(" M file-d"),
|
||||
Equals(" ?? file-e"),
|
||||
Equals(" ?? file-f"),
|
||||
).
|
||||
NavigateToLine(Contains("file-b")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
@ -41,27 +42,29 @@ var StageRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// Stage
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains(" A ").Contains("file-b").IsSelected(),
|
||||
Contains("▼ dir2").IsSelected(),
|
||||
Contains(" A ").Contains("file-c").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" A file-b").IsSelected(),
|
||||
Equals(" ▼ dir2").IsSelected(),
|
||||
Equals(" A file-c").IsSelected(),
|
||||
// Staged because dir2 was part of the selection when he hit space
|
||||
Contains(" M ").Contains("file-d"),
|
||||
Contains("??").Contains("file-e"),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals(" M file-d"),
|
||||
Equals(" ?? file-e"),
|
||||
Equals(" ?? file-f"),
|
||||
).
|
||||
// Unstage; back to everything being unstaged
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains(" ??").Contains("file-b").IsSelected(),
|
||||
Contains("▼ dir2").IsSelected(),
|
||||
Contains(" ??").Contains("file-c").IsSelected(),
|
||||
Contains(" M").Contains("file-d"),
|
||||
Contains("??").Contains("file-e"),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b").IsSelected(),
|
||||
Equals(" ▼ dir2").IsSelected(),
|
||||
Equals(" ?? file-c").IsSelected(),
|
||||
Equals(" M file-d"),
|
||||
Equals(" ?? file-e"),
|
||||
Equals(" ?? file-f"),
|
||||
).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("dir2")).
|
||||
@ -69,38 +72,41 @@ var StageRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// Collapse the directory
|
||||
PressEnter().
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains(" ??").Contains("file-b"),
|
||||
Contains("▶ dir2").IsSelected(),
|
||||
Contains("??").Contains("file-e"),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b"),
|
||||
Equals(" ▶ dir2").IsSelected(),
|
||||
Equals(" ?? file-e"),
|
||||
Equals(" ?? file-f"),
|
||||
).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("file-e")).
|
||||
// Stage
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains(" ??").Contains("file-b"),
|
||||
Contains("▶ dir2").IsSelected(),
|
||||
Contains("A ").Contains("file-e").IsSelected(),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b"),
|
||||
Equals(" ▶ dir2").IsSelected(),
|
||||
Equals(" A file-e").IsSelected(),
|
||||
Equals(" ?? file-f"),
|
||||
).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("dir2")).
|
||||
// Expand the directory again to verify it's been staged
|
||||
PressEnter().
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ??").Contains("file-a"),
|
||||
Contains(" ??").Contains("file-b"),
|
||||
Contains("▼ dir2").IsSelected(),
|
||||
Contains(" A ").Contains("file-c"),
|
||||
Contains(" M ").Contains("file-d"),
|
||||
Contains("A ").Contains("file-e"),
|
||||
Contains("??").Contains("file-f"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ?? file-a"),
|
||||
Equals(" ?? file-b"),
|
||||
Equals(" ▼ dir2").IsSelected(),
|
||||
Equals(" A file-c"),
|
||||
Equals(" M file-d"),
|
||||
Equals(" A file-e"),
|
||||
Equals(" ?? file-f"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -29,8 +29,9 @@ var FilterByFileStatus = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Lines(
|
||||
Equals("A file-staged-but-untracked").IsSelected(),
|
||||
Equals(" M file-tracked"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A file-staged-but-untracked"),
|
||||
Equals(" M file-tracked"),
|
||||
).
|
||||
Press(keys.Files.OpenStatusFilter).
|
||||
Tap(func() {
|
||||
@ -50,8 +51,9 @@ var FilterByFileStatus = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Equals("A file-staged-but-untracked").IsSelected(),
|
||||
Equals(" M file-tracked"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A file-staged-but-untracked"),
|
||||
Equals(" M file-tracked"),
|
||||
).
|
||||
Press(keys.Files.OpenStatusFilter).
|
||||
Tap(func() {
|
||||
@ -61,8 +63,9 @@ var FilterByFileStatus = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Equals("A file-staged-but-untracked").IsSelected(),
|
||||
Equals(" M file-tracked"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A file-staged-but-untracked"),
|
||||
Equals(" M file-tracked"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -61,15 +61,17 @@ var NestedFilter = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains(`apple`).IsSelected(),
|
||||
Contains(`grape`),
|
||||
Contains(`orange`),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A apple"),
|
||||
Equals(" A grape"),
|
||||
Equals(" A orange"),
|
||||
).
|
||||
FilterOrSearch("grape").
|
||||
Lines(
|
||||
Contains(`apple`),
|
||||
Contains(`grape`).IsSelected(),
|
||||
Contains(`orange`),
|
||||
Equals("▼ /"),
|
||||
Equals(" A apple"),
|
||||
Equals(" A grape").IsSelected(),
|
||||
Equals(" A orange"),
|
||||
).
|
||||
PressEnter()
|
||||
|
||||
@ -87,9 +89,10 @@ var NestedFilter = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains(`apple`),
|
||||
Contains(`grape`).IsSelected(),
|
||||
Contains(`orange`),
|
||||
Equals("▼ /"),
|
||||
Equals(" A apple"),
|
||||
Equals(" A grape").IsSelected(),
|
||||
Equals(" A orange"),
|
||||
).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 'grape'"))
|
||||
@ -100,9 +103,10 @@ var NestedFilter = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Search().IsInvisible()
|
||||
}).
|
||||
Lines(
|
||||
Contains(`apple`),
|
||||
Contains(`grape`).IsSelected(),
|
||||
Contains(`orange`),
|
||||
Equals("▼ /"),
|
||||
Equals(" A apple"),
|
||||
Equals(" A grape").IsSelected(),
|
||||
Equals(" A orange"),
|
||||
).
|
||||
// escape to sub-commits view
|
||||
PressEscape()
|
||||
|
@ -69,13 +69,15 @@ var NestedFilterTransient = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains(`file-one`).IsSelected(),
|
||||
Contains(`file-two`),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A file-one"),
|
||||
Equals(" A file-two"),
|
||||
).
|
||||
FilterOrSearch("two").
|
||||
Lines(
|
||||
Contains(`file-one`),
|
||||
Contains(`file-two`).IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" A file-one"),
|
||||
Equals(" A file-two").IsSelected(),
|
||||
)
|
||||
|
||||
t.Views().Branches().
|
||||
@ -96,8 +98,9 @@ var NestedFilterTransient = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
IsFocused().
|
||||
// the search on the commit-files context has been cancelled
|
||||
Lines(
|
||||
Contains(`file-one`).IsSelected(),
|
||||
Contains(`file-two`),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A file-one"),
|
||||
Equals(" A file-two"),
|
||||
).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsInvisible()
|
||||
|
@ -27,17 +27,20 @@ func postFilterTest(t *TestDriver) {
|
||||
Contains(`only filterFile`).IsSelected(),
|
||||
Contains(`both files`),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressEnter()
|
||||
SelectNextItem()
|
||||
|
||||
// we only show the filtered file's changes in the main view
|
||||
t.Views().Main().
|
||||
Content(Contains("filterFile").DoesNotContain("otherFile"))
|
||||
|
||||
t.Views().Commits().
|
||||
PressEnter()
|
||||
|
||||
// when you click into the commit itself, you see all files from that commit
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Equals("▼ /"),
|
||||
Contains(`filterFile`),
|
||||
Contains(`otherFile`),
|
||||
)
|
||||
|
@ -26,9 +26,11 @@ var ApplyInReverse = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file1").IsSelected(),
|
||||
Contains("file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A file1"),
|
||||
Equals(" A file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Information().Content(Contains("Building patch"))
|
||||
|
@ -34,9 +34,11 @@ var ApplyInReverseWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("M").Contains("file1").IsSelected(),
|
||||
Contains("M").Contains("file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" M file1"),
|
||||
Equals(" M file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
// Add both files to the patch; the first will conflict, the second won't
|
||||
PressPrimaryAction().
|
||||
Tap(func() {
|
||||
@ -61,7 +63,7 @@ var ApplyInReverseWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("UU").Contains("file1").IsSelected(),
|
||||
Equals("UU file1").IsSelected(),
|
||||
).
|
||||
PressEnter()
|
||||
|
||||
@ -81,9 +83,11 @@ var ApplyInReverseWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("M").Contains("file1").IsSelected(),
|
||||
Contains("M").Contains("file2"),
|
||||
)
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" M file1"),
|
||||
Equals(" M file2"),
|
||||
).
|
||||
SelectNextItem()
|
||||
|
||||
t.Views().Main().
|
||||
ContainsLines(
|
||||
|
@ -31,10 +31,12 @@ var MoveRangeToIndex = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("M file1").IsSelected(),
|
||||
Contains("A file2"),
|
||||
Contains("A file3"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" M file1"),
|
||||
Equals(" A file2"),
|
||||
Equals(" A file3"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("file2")).
|
||||
PressPrimaryAction()
|
||||
@ -55,8 +57,9 @@ var MoveRangeToIndex = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("file1").IsSelected(),
|
||||
Contains("file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" M file1"),
|
||||
Equals(" A file2"),
|
||||
)
|
||||
|
||||
t.Views().Main().
|
||||
|
@ -66,11 +66,12 @@ var MoveToEarlierCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains(" M file1"),
|
||||
Contains(" D file2"),
|
||||
Contains(" A file3"),
|
||||
Contains("A unrelated-file"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir"),
|
||||
Equals(" M file1"),
|
||||
Equals(" D file2"),
|
||||
Equals(" A file3"),
|
||||
Equals(" A unrelated-file"),
|
||||
).
|
||||
PressEscape()
|
||||
|
||||
|
@ -66,11 +66,12 @@ var MoveToEarlierCommitNoKeepEmpty = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains(" M file1"),
|
||||
Contains(" D file2"),
|
||||
Contains(" A file3"),
|
||||
Contains("A unrelated-file"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir"),
|
||||
Equals(" M file1"),
|
||||
Equals(" D file2"),
|
||||
Equals(" A file3"),
|
||||
Equals(" A unrelated-file"),
|
||||
).
|
||||
PressEscape()
|
||||
},
|
||||
|
@ -26,9 +26,11 @@ var MoveToIndex = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file1").IsSelected(),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("file1"),
|
||||
Contains("file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Information().Content(Contains("Building patch"))
|
||||
|
@ -66,11 +66,12 @@ var MoveToLaterCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("dir").IsSelected(),
|
||||
Contains(" M file1"),
|
||||
Contains(" D file2"),
|
||||
Contains(" A file3"),
|
||||
Contains("A unrelated-file"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir"),
|
||||
Equals(" M file1"),
|
||||
Equals(" D file2"),
|
||||
Equals(" A file3"),
|
||||
Equals(" A unrelated-file"),
|
||||
).
|
||||
PressEscape()
|
||||
|
||||
|
@ -67,9 +67,11 @@ var MoveToLaterCommitPartialHunk = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file1").IsSelected(),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("file1"),
|
||||
Contains("unrelated-file"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Tap(func() {
|
||||
t.Views().Main().
|
||||
Content(Contains("+1st line\n 2nd line"))
|
||||
|
@ -26,9 +26,11 @@ var RemoveFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file1").IsSelected(),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("file1"),
|
||||
Contains("file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Information().Content(Contains("Building patch"))
|
||||
|
@ -27,9 +27,10 @@ var SelectAllFiles = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file1").IsSelected(),
|
||||
Contains("file2"),
|
||||
Contains("file3"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A file1"),
|
||||
Equals(" A file2"),
|
||||
Equals(" A file3"),
|
||||
).
|
||||
Press(keys.Files.ToggleStagedAll)
|
||||
|
||||
|
@ -33,10 +33,12 @@ var SpecificSelection = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("direct-file").IsSelected(),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("direct-file"),
|
||||
Contains("hunk-file"),
|
||||
Contains("line-file"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction().
|
||||
Tap(func() {
|
||||
t.Views().Information().Content(Contains("Building patch"))
|
||||
|
@ -34,28 +34,30 @@ var ToggleRange = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("▼ dir1").IsSelected(),
|
||||
Contains(" A").Contains("file1-a"),
|
||||
Contains(" A").Contains("file2-a"),
|
||||
Contains(" A").Contains("file3-a"),
|
||||
Contains("▼ dir2"),
|
||||
Contains(" A").Contains("file1-b"),
|
||||
Contains(" A").Contains("file2-b"),
|
||||
Contains(" A").Contains("file3-b"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" A file1-a"),
|
||||
Equals(" A file2-a"),
|
||||
Equals(" A file3-a"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" A file1-b"),
|
||||
Equals(" A file2-b"),
|
||||
Equals(" A file3-b"),
|
||||
).
|
||||
NavigateToLine(Contains("file1-a")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("file3-a")).
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ●").Contains("file1-a").IsSelected(),
|
||||
Contains(" ●").Contains("file2-a").IsSelected(),
|
||||
Contains(" ●").Contains("file3-a").IsSelected(),
|
||||
Contains("▼ dir2"),
|
||||
Contains(" A").Contains("file1-b"),
|
||||
Contains(" A").Contains("file2-b"),
|
||||
Contains(" A").Contains("file3-b"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ● file1-a").IsSelected(),
|
||||
Equals(" ● file2-a").IsSelected(),
|
||||
Equals(" ● file3-a").IsSelected(),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" A file1-b"),
|
||||
Equals(" A file2-b"),
|
||||
Equals(" A file3-b"),
|
||||
).
|
||||
PressEscape().
|
||||
NavigateToLine(Contains("file3-b")).
|
||||
@ -69,39 +71,42 @@ var ToggleRange = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("▼ dir1"),
|
||||
Contains(" ●").Contains("file1-a"),
|
||||
Contains(" ●").Contains("file2-a"),
|
||||
Contains(" ●").Contains("file3-a"),
|
||||
Contains("▼ dir2"),
|
||||
Contains(" A").Contains("file1-b"),
|
||||
Contains(" A").Contains("file2-b"),
|
||||
Contains(" ◐").Contains("file3-b").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1"),
|
||||
Equals(" ● file1-a"),
|
||||
Equals(" ● file2-a"),
|
||||
Equals(" ● file3-a"),
|
||||
Equals(" ▼ dir2"),
|
||||
Equals(" A file1-b"),
|
||||
Equals(" A file2-b"),
|
||||
Equals(" ◐ file3-b").IsSelected(),
|
||||
).
|
||||
NavigateToLine(Contains("dir1")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("dir2")).
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("▼ dir1").IsSelected(),
|
||||
Contains(" ●").Contains("file1-a").IsSelected(),
|
||||
Contains(" ●").Contains("file2-a").IsSelected(),
|
||||
Contains(" ●").Contains("file3-a").IsSelected(),
|
||||
Contains("▼ dir2").IsSelected(),
|
||||
Contains(" ●").Contains("file1-b"),
|
||||
Contains(" ●").Contains("file2-b"),
|
||||
Contains(" ●").Contains("file3-b"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1").IsSelected(),
|
||||
Equals(" ● file1-a").IsSelected(),
|
||||
Equals(" ● file2-a").IsSelected(),
|
||||
Equals(" ● file3-a").IsSelected(),
|
||||
Equals(" ▼ dir2").IsSelected(),
|
||||
Equals(" ● file1-b"),
|
||||
Equals(" ● file2-b"),
|
||||
Equals(" ● file3-b"),
|
||||
).
|
||||
PressPrimaryAction().
|
||||
Lines(
|
||||
Contains("▼ dir1").IsSelected(),
|
||||
Contains(" A").Contains("file1-a").IsSelected(),
|
||||
Contains(" A").Contains("file2-a").IsSelected(),
|
||||
Contains(" A").Contains("file3-a").IsSelected(),
|
||||
Contains("▼ dir2").IsSelected(),
|
||||
Contains(" A").Contains("file1-b"),
|
||||
Contains(" A").Contains("file2-b"),
|
||||
Contains(" A").Contains("file3-b"),
|
||||
Equals("▼ /"),
|
||||
Equals(" ▼ dir1").IsSelected(),
|
||||
Equals(" A file1-a").IsSelected(),
|
||||
Equals(" A file2-a").IsSelected(),
|
||||
Equals(" A file3-a").IsSelected(),
|
||||
Equals(" ▼ dir2").IsSelected(),
|
||||
Equals(" A file1-b"),
|
||||
Equals(" A file2-b"),
|
||||
Equals(" A file3-b"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -48,9 +48,11 @@ var Patch = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file1").IsSelected(),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("file1"),
|
||||
Contains("file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Information().Content(Contains("Building patch"))
|
||||
|
@ -22,9 +22,11 @@ var DiscardAllChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file1").IsSelected(),
|
||||
Contains("file2"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" M file1"),
|
||||
Equals(" M file2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressEnter()
|
||||
|
||||
t.Views().Staging().
|
||||
@ -44,7 +46,7 @@ var DiscardAllChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// because there are no more changes in file1 we switch to file2
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains("file2").IsSelected(),
|
||||
Equals(" M file2"),
|
||||
)
|
||||
}).
|
||||
// assert we are still in the staging panel, but now looking at the changes of the other file
|
||||
|
@ -30,9 +30,11 @@ var ApplyPatch = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("myfile").IsSelected(),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Contains("myfile"),
|
||||
Contains("myfile2"),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Information().Content(Contains("Building patch"))
|
||||
|
@ -23,8 +23,9 @@ var StashAndKeepIndex = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains("file-staged"),
|
||||
Contains("file-unstaged"),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file-staged"),
|
||||
Equals(" M file-unstaged"),
|
||||
).
|
||||
Press(keys.Files.ViewStashOptions)
|
||||
|
||||
@ -39,7 +40,7 @@ var StashAndKeepIndex = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains("file-staged"),
|
||||
Equals("M file-staged"),
|
||||
)
|
||||
|
||||
t.Views().Stash().
|
||||
@ -49,8 +50,9 @@ var StashAndKeepIndex = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file-staged"),
|
||||
Contains("file-unstaged"),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file-staged"),
|
||||
Equals(" M file-unstaged"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -22,8 +22,9 @@ var StashIncludingUntrackedFiles = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains("file_1"),
|
||||
Contains("file_2"),
|
||||
Equals("▼ /"),
|
||||
Equals(" A file_1"),
|
||||
Equals(" ?? file_2"),
|
||||
).
|
||||
Press(keys.Files.ViewStashOptions)
|
||||
|
||||
|
@ -23,8 +23,9 @@ var StashStaged = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains("file-staged"),
|
||||
Contains("file-unstaged"),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file-staged"),
|
||||
Equals(" M file-unstaged"),
|
||||
).
|
||||
Press(keys.Files.ViewStashOptions)
|
||||
|
||||
@ -39,7 +40,7 @@ var StashStaged = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains("file-unstaged"),
|
||||
Equals(" M file-unstaged"),
|
||||
)
|
||||
|
||||
t.Views().Stash().
|
||||
|
@ -23,8 +23,9 @@ var StashUnstaged = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains("file-staged"),
|
||||
Contains("file-unstaged"),
|
||||
Equals("▼ /"),
|
||||
Equals(" M file-staged"),
|
||||
Equals(" M file-unstaged"),
|
||||
).
|
||||
Press(keys.Files.ViewStashOptions)
|
||||
|
||||
|
@ -44,9 +44,11 @@ var Add = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().Focus().
|
||||
Lines(
|
||||
Contains(".gitmodules").IsSelected(),
|
||||
Contains("my_submodule_path (submodule)"),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" A .gitmodules"),
|
||||
Equals(" A my_submodule_path (submodule)"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Tap(func() {
|
||||
t.Views().Main().Content(
|
||||
Contains("[submodule \"my_submodule\"]").
|
||||
|
@ -35,9 +35,11 @@ var Remove = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().Focus().
|
||||
Lines(
|
||||
MatchesRegexp(`M.*\.gitmodules`).IsSelected(),
|
||||
MatchesRegexp(`D.*my_submodule_path`),
|
||||
)
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" M .gitmodules"),
|
||||
Equals(" D my_submodule_path"),
|
||||
).
|
||||
SelectNextItem()
|
||||
|
||||
t.Views().Main().Content(
|
||||
Contains("-[submodule \"my_submodule_name\"]").
|
||||
|
@ -39,9 +39,10 @@ var RemoveNested = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().IsFocused().
|
||||
Lines(
|
||||
Contains("modules").IsSelected(),
|
||||
MatchesRegexp(`D.*innerSubPath`),
|
||||
MatchesRegexp(`M.*\.gitmodules`),
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ▼ modules"),
|
||||
Equals(" D innerSubPath"),
|
||||
Equals(" M .gitmodules"),
|
||||
).
|
||||
NavigateToLine(Contains(".gitmodules"))
|
||||
|
||||
|
@ -71,15 +71,17 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().Focus().
|
||||
Lines(
|
||||
MatchesRegexp(` M.*my_submodule_path \(submodule\)`),
|
||||
Contains("other_file").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" M my_submodule_path (submodule)"),
|
||||
Equals(" ?? other_file").IsSelected(),
|
||||
).
|
||||
// Verify we can't use range select on submodules
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
SelectPreviousItem().
|
||||
Lines(
|
||||
MatchesRegexp(` M.*my_submodule_path \(submodule\)`).IsSelected(),
|
||||
Contains("other_file").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" M my_submodule_path (submodule)").IsSelected(),
|
||||
Equals(" ?? other_file").IsSelected(),
|
||||
).
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
@ -87,8 +89,9 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
}).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
Lines(
|
||||
MatchesRegexp(` M.*my_submodule_path \(submodule\)`).IsSelected(),
|
||||
Contains("other_file"),
|
||||
Equals("▼ /"),
|
||||
Equals(" M my_submodule_path (submodule)").IsSelected(),
|
||||
Equals(" ?? other_file"),
|
||||
).
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
@ -98,7 +101,7 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("other_file").IsSelected(),
|
||||
Equals("?? other_file").IsSelected(),
|
||||
)
|
||||
|
||||
t.Views().Submodules().Focus().
|
||||
|
@ -57,8 +57,9 @@ var UndoCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains("A file"),
|
||||
Contains(" M other-file"),
|
||||
Equals("▼ /"),
|
||||
Equals(" A file"),
|
||||
Equals(" M other-file"),
|
||||
)
|
||||
|
||||
t.Views().Commits().Focus().
|
||||
@ -71,7 +72,7 @@ var UndoCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains(" M other-file"),
|
||||
Equals(" M other-file"),
|
||||
)
|
||||
|
||||
// Undo again, this time discarding the original change before redoing again
|
||||
@ -84,14 +85,15 @@ var UndoCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().Focus().
|
||||
Lines(
|
||||
Contains("A file"),
|
||||
Contains(" M other-file").IsSelected(),
|
||||
Equals("▼ /"),
|
||||
Equals(" A file"),
|
||||
Equals(" M other-file").IsSelected(),
|
||||
).
|
||||
Press(keys.Universal.PrevItem).
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(confirmDiscardFile).
|
||||
Lines(
|
||||
Contains(" M other-file"),
|
||||
Equals(" M other-file"),
|
||||
).
|
||||
Press(keys.Universal.Redo).
|
||||
Tap(confirmRedo)
|
||||
@ -104,7 +106,7 @@ var UndoCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Files().
|
||||
Lines(
|
||||
Contains(" M other-file"),
|
||||
Equals(" M other-file"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user