1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-09 13:47:11 +02:00

more generics

This commit is contained in:
Jesse Duffield 2022-03-19 16:34:46 +11:00
parent eda8f4a5d4
commit bf4f06ab4e
21 changed files with 303 additions and 198 deletions

2
go.mod
View File

@ -14,7 +14,7 @@ require (
github.com/gookit/color v1.4.2 github.com/gookit/color v1.4.2
github.com/imdario/mergo v0.3.11 github.com/imdario/mergo v0.3.11
github.com/integrii/flaggy v1.4.0 github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4
github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e

4
go.sum
View File

@ -66,8 +66,8 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM
github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f h1:VZkNxrfkR344djm4Ju7QuKLXxZlaaOaNCrAWVRc1gvU= github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 h1:scclO0fuRMsIdYr6Gg+9LS1S1ZO93tHKQSbErWQWQ4s=
github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI=

View File

@ -13,6 +13,7 @@ import (
"log" "log"
"os" "os"
"github.com/jesseduffield/generics/maps"
"github.com/jesseduffield/generics/slices" "github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/app" "github.com/jesseduffield/lazygit/pkg/app"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
@ -174,11 +175,12 @@ outer:
bindings []*types.Binding bindings []*types.Binding
} }
groupedBindings := make([]groupedBindingsType, 0, len(contextAndViewBindingMap)) groupedBindings := maps.MapToSlice(
contextAndViewBindingMap,
for contextAndView, contextBindings := range contextAndViewBindingMap { func(contextAndView contextAndViewType, contextBindings []*types.Binding) groupedBindingsType {
groupedBindings = append(groupedBindings, groupedBindingsType{contextAndView: contextAndView, bindings: contextBindings}) return groupedBindingsType{contextAndView: contextAndView, bindings: contextBindings}
} },
)
slices.SortFunc(groupedBindings, func(a, b groupedBindingsType) bool { slices.SortFunc(groupedBindings, func(a, b groupedBindingsType) bool {
first := a.contextAndView first := a.contextAndView

View File

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/loaders"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
@ -46,10 +47,9 @@ func (self *WorkingTreeCommands) StageFile(path string) error {
} }
func (self *WorkingTreeCommands) StageFiles(paths []string) error { func (self *WorkingTreeCommands) StageFiles(paths []string) error {
quotedPaths := make([]string, len(paths)) quotedPaths := slices.Map(paths, func(path string) string {
for i, path := range paths { return self.cmd.Quote(path)
quotedPaths[i] = self.cmd.Quote(path) })
}
return self.cmd.New(fmt.Sprintf("git add -- %s", strings.Join(quotedPaths, " "))).Run() return self.cmd.New(fmt.Sprintf("git add -- %s", strings.Join(quotedPaths, " "))).Run()
} }

View File

@ -66,13 +66,13 @@ outer:
if strings.EqualFold(reflogBranch.Name, branch.Name) { if strings.EqualFold(reflogBranch.Name, branch.Name) {
branch.Recency = reflogBranch.Recency branch.Recency = reflogBranch.Recency
branchesWithRecency = append(branchesWithRecency, branch) branchesWithRecency = append(branchesWithRecency, branch)
branches = append(branches[0:j], branches[j+1:]...) branches = slices.Remove(branches, j)
continue outer continue outer
} }
} }
} }
branches = append(branchesWithRecency, branches...) branches = slices.Prepend(branches, branchesWithRecency...)
foundHead := false foundHead := false
for i, branch := range branches { for i, branch := range branches {
@ -159,7 +159,7 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
trimmedOutput := strings.TrimSpace(output) trimmedOutput := strings.TrimSpace(output)
outputLines := strings.Split(trimmedOutput, "\n") outputLines := strings.Split(trimmedOutput, "\n")
branches := slices.FilterMap(outputLines, func(line string) (*models.Branch, bool) { return slices.FilterMap(outputLines, func(line string) (*models.Branch, bool) {
if line == "" { if line == "" {
return nil, false return nil, false
} }
@ -174,8 +174,6 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
return obtainBranch(split), true return obtainBranch(split), true
}) })
return branches
} }
// TODO: only look at the new reflog commits, and otherwise store the recencies in // TODO: only look at the new reflog commits, and otherwise store the recencies in
@ -184,17 +182,21 @@ func (self *BranchLoader) obtainReflogBranches(reflogCommits []*models.Commit) [
foundBranches := set.New[string]() foundBranches := set.New[string]()
re := regexp.MustCompile(`checkout: moving from ([\S]+) to ([\S]+)`) re := regexp.MustCompile(`checkout: moving from ([\S]+) to ([\S]+)`)
reflogBranches := make([]*models.Branch, 0, len(reflogCommits)) reflogBranches := make([]*models.Branch, 0, len(reflogCommits))
for _, commit := range reflogCommits { for _, commit := range reflogCommits {
if match := re.FindStringSubmatch(commit.Name); len(match) == 3 { match := re.FindStringSubmatch(commit.Name)
recency := utils.UnixToTimeAgo(commit.UnixTimestamp) if len(match) != 3 {
for _, branchName := range match[1:] { continue
if !foundBranches.Includes(branchName) { }
foundBranches.Add(branchName)
reflogBranches = append(reflogBranches, &models.Branch{ recency := utils.UnixToTimeAgo(commit.UnixTimestamp)
Recency: recency, for _, branchName := range match[1:] {
Name: branchName, if !foundBranches.Includes(branchName) {
}) foundBranches.Add(branchName)
} reflogBranches = append(reflogBranches, &models.Branch{
Recency: recency,
Name: branchName,
})
} }
} }
} }

View File

@ -4,9 +4,11 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/common"
"github.com/samber/lo"
) )
type CommitFileLoader struct { type CommitFileLoader struct {
@ -33,25 +35,22 @@ func (self *CommitFileLoader) GetFilesInDiff(from string, to string, reverse boo
return nil, err return nil, err
} }
return self.getCommitFilesFromFilenames(filenames), nil return getCommitFilesFromFilenames(filenames), nil
} }
// filenames string is something like "file1\nfile2\nfile3" // filenames string is something like "MM\x00file1\x00MU\x00file2\x00AA\x00file3\x00"
func (self *CommitFileLoader) getCommitFilesFromFilenames(filenames string) []*models.CommitFile { // so we need to split it by the null character and then map each status-name pair to a commit file
commitFiles := make([]*models.CommitFile, 0) func getCommitFilesFromFilenames(filenames string) []*models.CommitFile {
lines := strings.Split(strings.TrimRight(filenames, "\x00"), "\x00") lines := strings.Split(strings.TrimRight(filenames, "\x00"), "\x00")
n := len(lines) if len(lines) == 1 {
for i := 0; i < n-1; i += 2 { return []*models.CommitFile{}
// typical result looks like 'A my_file' meaning my_file was added
changeStatus := lines[i]
name := lines[i+1]
commitFiles = append(commitFiles, &models.CommitFile{
Name: name,
ChangeStatus: changeStatus,
})
} }
return commitFiles // typical result looks like 'A my_file' meaning my_file was added
return slices.Map(lo.Chunk(lines, 2), func(chunk []string) *models.CommitFile {
return &models.CommitFile{
ChangeStatus: chunk[0],
Name: chunk[1],
}
})
} }

View File

@ -0,0 +1,71 @@
package loaders
import (
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/stretchr/testify/assert"
)
func TestGetCommitFilesFromFilenames(t *testing.T) {
tests := []struct {
testName string
input string
output []*models.CommitFile
}{
{
testName: "no files",
input: "",
output: []*models.CommitFile{},
},
{
testName: "one file",
input: "MM\x00Myfile\x00",
output: []*models.CommitFile{
{
Name: "Myfile",
ChangeStatus: "MM",
},
},
},
{
testName: "two files",
input: "MM\x00Myfile\x00M \x00MyOtherFile\x00",
output: []*models.CommitFile{
{
Name: "Myfile",
ChangeStatus: "MM",
},
{
Name: "MyOtherFile",
ChangeStatus: "M ",
},
},
},
{
testName: "three files",
input: "MM\x00Myfile\x00M \x00MyOtherFile\x00 M\x00YetAnother\x00",
output: []*models.CommitFile{
{
Name: "Myfile",
ChangeStatus: "MM",
},
{
Name: "MyOtherFile",
ChangeStatus: "M ",
},
{
Name: "YetAnother",
ChangeStatus: " M",
},
},
},
}
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
result := getCommitFilesFromFilenames(test.input)
assert.Equal(t, test.output, result)
})
}
}

View File

@ -9,6 +9,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/commands/types/enums"
@ -200,10 +201,9 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
return nil, nil return nil, nil
} }
commitShas := make([]string, len(commits)) commitShas := slices.Map(commits, func(commit *models.Commit) string {
for i, commit := range commits { return commit.Sha
commitShas[i] = commit.Sha })
}
// note that we're not filtering these as we do non-rebasing commits just because // note that we're not filtering these as we do non-rebasing commits just because
// I suspect that will cause some damage // I suspect that will cause some damage

View File

@ -11,24 +11,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func NewDummyCommitLoader() *CommitLoader {
cmn := utils.NewDummyCommon()
return &CommitLoader{
Common: cmn,
cmd: nil,
getCurrentBranchName: func() (string, string, error) { return "master", "master", nil },
getRebaseMode: func() (enums.RebaseMode, error) { return enums.REBASE_MODE_NONE, nil },
dotGitDir: ".git",
readFile: func(filename string) ([]byte, error) {
return []byte(""), nil
},
walkFiles: func(root string, fn filepath.WalkFunc) error {
return nil
},
}
}
const commitsOutput = `0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield| (HEAD -> better-tests)|b21997d6b4cbdf84b149|better typing for rebase mode const commitsOutput = `0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield| (HEAD -> better-tests)|b21997d6b4cbdf84b149|better typing for rebase mode
b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164|1640824515|Jesse Duffield| (origin/better-tests)|e94e8fc5b6fab4cb755f|fix logging b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164|1640824515|Jesse Duffield| (origin/better-tests)|e94e8fc5b6fab4cb755f|fix logging
e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield||d8084cd558925eb7c9c3|refactor e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield||d8084cd558925eb7c9c3|refactor

View File

@ -1,8 +1,7 @@
package loaders package loaders
import ( import (
"strings" "github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/common"
@ -27,25 +26,18 @@ func NewTagLoader(
func (self *TagLoader) GetTags() ([]*models.Tag, error) { func (self *TagLoader) GetTags() ([]*models.Tag, error) {
// get remote branches, sorted by creation date (descending) // get remote branches, sorted by creation date (descending)
// see: https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---sortltkeygt // see: https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---sortltkeygt
remoteBranchesStr, err := self.cmd.New(`git tag --list --sort=-creatordate`).DontLog().RunWithOutput() tagsOutput, err := self.cmd.New(`git tag --list --sort=-creatordate`).DontLog().RunWithOutput()
if err != nil { if err != nil {
return nil, err return nil, err
} }
content := utils.TrimTrailingNewline(remoteBranchesStr) split := utils.SplitLines(tagsOutput)
if content == "" {
return nil, nil
}
split := strings.Split(content, "\n") tags := slices.Map(split, func(tagName string) *models.Tag {
return &models.Tag{
// first step is to get our remotes from go-git
tags := make([]*models.Tag, len(split))
for i, tagName := range split {
tags[i] = &models.Tag{
Name: tagName, Name: tagName,
} }
} })
return tags, nil return tags, nil
} }

View File

@ -0,0 +1,68 @@
package loaders
import (
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/stretchr/testify/assert"
)
const tagsOutput = `v0.34
v0.33
v0.32.2
v0.32.1
v0.32
testtag
`
func TestGetTags(t *testing.T) {
type scenario struct {
testName string
runner *oscommands.FakeCmdObjRunner
expectedTags []*models.Tag
expectedError error
}
scenarios := []scenario{
{
testName: "should return no tags if there are none",
runner: oscommands.NewFakeRunner(t).
Expect(`git tag --list --sort=-creatordate`, "", nil),
expectedTags: []*models.Tag{},
expectedError: nil,
},
{
testName: "should return tags if present",
runner: oscommands.NewFakeRunner(t).
Expect(`git tag --list --sort=-creatordate`, tagsOutput, nil),
expectedTags: []*models.Tag{
{Name: "v0.34"},
{Name: "v0.33"},
{Name: "v0.32.2"},
{Name: "v0.32.1"},
{Name: "v0.32"},
{Name: "testtag"},
},
expectedError: nil,
},
}
for _, scenario := range scenarios {
scenario := scenario
t.Run(scenario.testName, func(t *testing.T) {
loader := &TagLoader{
Common: utils.NewDummyCommon(),
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
}
tags, err := loader.GetTags()
assert.Equal(t, scenario.expectedTags, tags)
assert.Equal(t, scenario.expectedError, err)
scenario.runner.CheckForMissingCalls()
})
}
}

View File

@ -12,6 +12,7 @@ import (
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/atotto/clipboard" "github.com/atotto/clipboard"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -173,15 +174,11 @@ func (c *OSCommand) FileExists(path string) (bool, error) {
// PipeCommands runs a heap of commands and pipes their inputs/outputs together like A | B | C // PipeCommands runs a heap of commands and pipes their inputs/outputs together like A | B | C
func (c *OSCommand) PipeCommands(commandStrings ...string) error { func (c *OSCommand) PipeCommands(commandStrings ...string) error {
cmds := make([]*exec.Cmd, len(commandStrings)) cmds := slices.Map(commandStrings, func(cmdString string) *exec.Cmd {
logCmdStr := "" return c.Cmd.New(cmdString).GetCmd()
for i, str := range commandStrings { })
if i > 0 {
logCmdStr += " | " logCmdStr := strings.Join(commandStrings, " | ")
}
logCmdStr += str
cmds[i] = c.Cmd.New(str).GetCmd()
}
c.LogCommand(logCmdStr, true) c.LogCommand(logCmdStr, true)
for i := 0; i < len(cmds)-1; i++ { for i := 0; i < len(cmds)-1; i++ {

View File

@ -4,6 +4,8 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/jesseduffield/generics/maps"
"github.com/jesseduffield/generics/slices"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -72,8 +74,9 @@ func (p *PatchManager) Start(from, to string, reverse bool, canRebase bool) {
func (p *PatchManager) addFileWhole(info *fileInfo) { func (p *PatchManager) addFileWhole(info *fileInfo) {
info.mode = WHOLE info.mode = WHOLE
lineCount := len(strings.Split(info.diff, "\n")) lineCount := len(strings.Split(info.diff, "\n"))
info.includedLineIndices = make([]int, lineCount)
// add every line index // add every line index
// TODO: add tests and then use lo.Range to simplify
info.includedLineIndices = make([]int, lineCount)
for i := 0; i < lineCount; i++ { for i := 0; i < lineCount; i++ {
info.includedLineIndices[i] = i info.includedLineIndices[i] = i
} }
@ -192,21 +195,15 @@ func (p *PatchManager) RenderPatchForFile(filename string, plain bool, reverse b
func (p *PatchManager) renderEachFilePatch(plain bool) []string { func (p *PatchManager) renderEachFilePatch(plain bool) []string {
// sort files by name then iterate through and render each patch // sort files by name then iterate through and render each patch
filenames := make([]string, len(p.fileInfoMap)) filenames := maps.Keys(p.fileInfoMap)
index := 0
for filename := range p.fileInfoMap {
filenames[index] = filename
index++
}
sort.Strings(filenames) sort.Strings(filenames)
output := []string{} patches := slices.Map(filenames, func(filename string) string {
for _, filename := range filenames { return p.RenderPatchForFile(filename, plain, false, true)
patch := p.RenderPatchForFile(filename, plain, false, true) })
if patch != "" { output := slices.Filter(patches, func(patch string) bool {
output = append(output, patch) return patch != ""
} })
}
return output return output
} }

View File

@ -4,9 +4,9 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -184,16 +184,21 @@ func parsePatch(patch string) ([]int, []int, []*PatchLine) {
// Render returns the coloured string of the diff with any selected lines highlighted // Render returns the coloured string of the diff with any selected lines highlighted
func (p *PatchParser) Render(firstLineIndex int, lastLineIndex int, incLineIndices []int) string { func (p *PatchParser) Render(firstLineIndex int, lastLineIndex int, incLineIndices []int) string {
renderedLines := make([]string, len(p.PatchLines)) contentToDisplay := slices.Some(p.PatchLines, func(line *PatchLine) bool {
for index, patchLine := range p.PatchLines { return line.Content != ""
selected := index >= firstLineIndex && index <= lastLineIndex })
included := lo.Contains(incLineIndices, index) if !contentToDisplay {
renderedLines[index] = patchLine.render(selected, included)
}
result := strings.Join(renderedLines, "\n")
if strings.TrimSpace(utils.Decolorise(result)) == "" {
return "" return ""
} }
renderedLines := lo.Map(p.PatchLines, func(patchLine *PatchLine, index int) string {
selected := index >= firstLineIndex && index <= lastLineIndex
included := lo.Contains(incLineIndices, index)
return patchLine.render(selected, included)
})
result := strings.Join(renderedLines, "\n")
return result return result
} }
@ -202,10 +207,9 @@ func (p *PatchParser) Render(firstLineIndex int, lastLineIndex int, incLineIndic
func (p *PatchParser) PlainRenderLines(firstLineIndex, lastLineIndex int) string { func (p *PatchParser) PlainRenderLines(firstLineIndex, lastLineIndex int) string {
linesToCopy := p.PatchLines[firstLineIndex : lastLineIndex+1] linesToCopy := p.PatchLines[firstLineIndex : lastLineIndex+1]
renderedLines := make([]string, len(linesToCopy)) renderedLines := slices.Map(linesToCopy, func(line *PatchLine) string {
for index, line := range linesToCopy { return line.Content
renderedLines[index] = line.Content })
}
return strings.Join(renderedLines, "\n") return strings.Join(renderedLines, "\n")
} }

View File

@ -6,6 +6,7 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/jesseduffield/generics/maps"
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
@ -231,10 +232,9 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro
} }
func (gui *Gui) optionsMapToString(optionsMap map[string]string) string { func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
optionsArray := make([]string, 0) optionsArray := maps.MapToSlice(optionsMap, func(key string, description string) string {
for key, description := range optionsMap { return key + ": " + description
optionsArray = append(optionsArray, key+": "+description) })
}
sort.Strings(optionsArray) sort.Strings(optionsArray)
return strings.Join(optionsArray, ", ") return strings.Join(optionsArray, ", ")
} }

View File

@ -38,13 +38,14 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
focus bool focus bool
}{ }{
{ {
testName: "no commits", testName: "no commits",
commits: []*models.Commit{}, commits: []*models.Commit{},
startIdx: 0, startIdx: 0,
length: 1, length: 1,
showGraph: false, showGraph: false,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
expected: "", cherryPickedCommitShaSet: set.New[string](),
expected: "",
}, },
{ {
testName: "some commits", testName: "some commits",
@ -52,10 +53,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
{Name: "commit1", Sha: "sha1"}, {Name: "commit1", Sha: "sha1"},
{Name: "commit2", Sha: "sha2"}, {Name: "commit2", Sha: "sha2"},
}, },
startIdx: 0, startIdx: 0,
length: 2, length: 2,
showGraph: false, showGraph: false,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
expected: formatExpected(` expected: formatExpected(`
sha1 commit1 sha1 commit1
sha2 commit2 sha2 commit2
@ -70,10 +72,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
{Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}},
{Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}},
}, },
startIdx: 0, startIdx: 0,
length: 5, length: 5,
showGraph: true, showGraph: true,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
expected: formatExpected(` expected: formatExpected(`
sha1 commit1 sha1 commit1
sha2 commit2 sha2 commit2
@ -91,10 +94,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
{Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}},
{Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}},
}, },
startIdx: 0, startIdx: 0,
length: 5, length: 5,
showGraph: true, showGraph: true,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
expected: formatExpected(` expected: formatExpected(`
sha1 pick commit1 sha1 pick commit1
sha2 pick commit2 sha2 pick commit2
@ -112,10 +116,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
{Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}},
{Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}},
}, },
startIdx: 1, startIdx: 1,
length: 10, length: 10,
showGraph: true, showGraph: true,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
expected: formatExpected(` expected: formatExpected(`
sha2 pick commit2 sha2 pick commit2
sha3 commit3 sha3 commit3
@ -132,10 +137,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
{Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}},
{Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}},
}, },
startIdx: 3, startIdx: 3,
length: 2, length: 2,
showGraph: true, showGraph: true,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
expected: formatExpected(` expected: formatExpected(`
sha4 commit4 sha4 commit4
sha5 commit5 sha5 commit5
@ -150,10 +156,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
{Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}},
{Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}},
}, },
startIdx: 0, startIdx: 0,
length: 2, length: 2,
showGraph: true, showGraph: true,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
expected: formatExpected(` expected: formatExpected(`
sha1 pick commit1 sha1 pick commit1
sha2 pick commit2 sha2 pick commit2
@ -168,10 +175,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
{Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}},
{Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}},
}, },
startIdx: 4, startIdx: 4,
length: 2, length: 2,
showGraph: true, showGraph: true,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
expected: formatExpected(` expected: formatExpected(`
sha5 commit5 sha5 commit5
`), `),
@ -185,10 +193,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
{Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}, Action: "pick"}, {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}, Action: "pick"},
{Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}},
}, },
startIdx: 0, startIdx: 0,
length: 2, length: 2,
showGraph: true, showGraph: true,
bisectInfo: git_commands.NewNullBisectInfo(), bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
expected: formatExpected(` expected: formatExpected(`
sha1 pick commit1 sha1 pick commit1
sha2 pick commit2 sha2 pick commit2

View File

@ -17,15 +17,6 @@ func SplitLines(multilineString string) []string {
return lines return lines
} }
// TrimTrailingNewline - Trims the trailing newline
// TODO: replace with `chomp` after refactor
func TrimTrailingNewline(str string) string {
if strings.HasSuffix(str, "\n") {
return str[:len(str)-1]
}
return str
}
// NormalizeLinefeeds - Removes all Windows and Mac style line feeds // NormalizeLinefeeds - Removes all Windows and Mac style line feeds
func NormalizeLinefeeds(str string) string { func NormalizeLinefeeds(str string) string {
str = strings.Replace(str, "\r\n", "\n", -1) str = strings.Replace(str, "\r\n", "\n", -1)

View File

@ -36,29 +36,6 @@ func TestSplitLines(t *testing.T) {
} }
} }
// TestTrimTrailingNewline is a function.
func TestTrimTrailingNewline(t *testing.T) {
type scenario struct {
str string
expected string
}
scenarios := []scenario{
{
"hello world !\n",
"hello world !",
},
{
"hello world !",
"hello world !",
},
}
for _, s := range scenarios {
assert.EqualValues(t, s.expected, TrimTrailingNewline(s.str))
}
}
// TestNormalizeLinefeeds is a function. // TestNormalizeLinefeeds is a function.
func TestNormalizeLinefeeds(t *testing.T) { func TestNormalizeLinefeeds(t *testing.T) {
type scenario struct { type scenario struct {

View File

@ -33,3 +33,21 @@ func TransformKeys[Key comparable, Value any, NewKey comparable](m map[Key]Value
} }
return output return output
} }
func MapToSlice[Key comparable, Value any, Mapped any](m map[Key]Value, f func(Key, Value) Mapped) []Mapped {
output := make([]Mapped, 0, len(m))
for key, value := range m {
output = append(output, f(key, value))
}
return output
}
func Filter[Key comparable, Value any](m map[Key]Value, f func(Key, Value) bool) map[Key]Value {
output := map[Key]Value{}
for key, value := range m {
if f(key, value) {
output[key] = value
}
}
return output
}

View File

@ -19,13 +19,9 @@ func NewFromSlice[T comparable](slice []T) *Set[T] {
return &Set[T]{hashMap: hashMap} return &Set[T]{hashMap: hashMap}
} }
func (s *Set[T]) Add(value T) { func (s *Set[T]) Add(values ...T) {
s.hashMap[value] = true for _, value := range values {
} s.hashMap[value] = true
func (s *Set[T]) AddSlice(slice []T) {
for _, value := range slice {
s.Add(value)
} }
} }

2
vendor/modules.txt vendored
View File

@ -120,7 +120,7 @@ github.com/integrii/flaggy
# github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
## explicit ## explicit
github.com/jbenet/go-context/io github.com/jbenet/go-context/io
# github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f # github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518
## explicit; go 1.18 ## explicit; go 1.18
github.com/jesseduffield/generics/maps github.com/jesseduffield/generics/maps
github.com/jesseduffield/generics/set github.com/jesseduffield/generics/set