2020-09-29 11:22:26 +02:00
package commands
import (
"fmt"
"strings"
2020-09-29 12:28:39 +02:00
"github.com/jesseduffield/lazygit/pkg/commands/models"
2020-09-29 11:22:26 +02:00
"github.com/jesseduffield/lazygit/pkg/utils"
)
2020-09-29 12:03:39 +02:00
// GetStatusFiles git status files
type GetStatusFileOptions struct {
NoRenames bool
}
2020-09-29 11:22:26 +02:00
func ( c * GitCommand ) GetStatusFiles ( opts GetStatusFileOptions ) [ ] * models . File {
// check if config wants us ignoring untracked files
untrackedFilesSetting := c . GetConfigValue ( "status.showUntrackedFiles" )
if untrackedFilesSetting == "" {
untrackedFilesSetting = "all"
}
untrackedFilesArg := fmt . Sprintf ( "--untracked-files=%s" , untrackedFilesSetting )
statusOutput , err := c . GitStatus ( GitStatusOptions { NoRenames : opts . NoRenames , UntrackedFilesArg : untrackedFilesArg } )
if err != nil {
c . Log . Error ( err )
}
statusStrings := utils . SplitLines ( statusOutput )
files := [ ] * models . File { }
for _ , statusString := range statusStrings {
if strings . HasPrefix ( statusString , "warning" ) {
c . Log . Warningf ( "warning when calling git status: %s" , statusString )
continue
}
change := statusString [ 0 : 2 ]
stagedChange := change [ 0 : 1 ]
unstagedChange := statusString [ 1 : 2 ]
filename := c . OSCommand . Unquote ( statusString [ 3 : ] )
untracked := utils . IncludesString ( [ ] string { "??" , "A " , "AM" } , change )
hasNoStagedChanges := utils . IncludesString ( [ ] string { " " , "U" , "?" } , stagedChange )
hasMergeConflicts := utils . IncludesString ( [ ] string { "DD" , "AA" , "UU" , "AU" , "UA" , "UD" , "DU" } , change )
hasInlineMergeConflicts := utils . IncludesString ( [ ] string { "UU" , "AA" } , change )
file := & models . File {
Name : filename ,
DisplayString : statusString ,
HasStagedChanges : ! hasNoStagedChanges ,
HasUnstagedChanges : unstagedChange != " " ,
Tracked : ! untracked ,
Deleted : unstagedChange == "D" || stagedChange == "D" ,
HasMergeConflicts : hasMergeConflicts ,
HasInlineMergeConflicts : hasInlineMergeConflicts ,
Type : c . OSCommand . FileType ( filename ) ,
ShortStatus : change ,
}
files = append ( files , file )
}
return files
}
// GitStatus returns the plaintext short status of the repo
type GitStatusOptions struct {
NoRenames bool
UntrackedFilesArg string
}
func ( c * GitCommand ) GitStatus ( opts GitStatusOptions ) ( string , error ) {
noRenamesFlag := ""
if opts . NoRenames {
noRenamesFlag = "--no-renames"
}
return c . OSCommand . RunCommandWithOutput ( "git status %s --porcelain %s" , opts . UntrackedFilesArg , noRenamesFlag )
}
// MergeStatusFiles merge status files
func ( c * GitCommand ) MergeStatusFiles ( oldFiles , newFiles [ ] * models . File , selectedFile * models . File ) [ ] * models . File {
if len ( oldFiles ) == 0 {
return newFiles
}
appendedIndexes := [ ] int { }
// retain position of files we already could see
result := [ ] * models . File { }
for _ , oldFile := range oldFiles {
for newIndex , newFile := range newFiles {
2020-09-29 12:03:39 +02:00
if utils . IncludesInt ( appendedIndexes , newIndex ) {
2020-09-29 11:22:26 +02:00
continue
}
// if we just staged B and in doing so created 'A -> B' and we are currently have oldFile: A and newFile: 'A -> B', we want to wait until we come across B so the our cursor isn't jumping anywhere
waitForMatchingFile := selectedFile != nil && newFile . IsRename ( ) && ! selectedFile . IsRename ( ) && newFile . Matches ( selectedFile ) && ! oldFile . Matches ( selectedFile )
if oldFile . Matches ( newFile ) && ! waitForMatchingFile {
result = append ( result , newFile )
appendedIndexes = append ( appendedIndexes , newIndex )
}
}
}
// append any new files to the end
for index , newFile := range newFiles {
2020-09-29 12:03:39 +02:00
if ! utils . IncludesInt ( appendedIndexes , index ) {
2020-09-29 11:22:26 +02:00
result = append ( result , newFile )
}
}
return result
}