mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-15 22:26:40 +02:00
render commit graph
This commit is contained in:
parent
2fc1498517
commit
802cfb1a04
@ -1,5 +1,5 @@
|
|||||||
# Go's proxy servers are not very up-to-date so that's why we use `GOPROXY=direct`
|
# Go's proxy servers are not very up-to-date so that's why we use `GOPROXY=direct`
|
||||||
# We specify the `awesome` branch to avoid the default behaviour of looking for a semver tag.
|
# We specify the `awesome` branch to avoid the default behaviour of looking for a semver tag.
|
||||||
GOPROXY=direct go get -u github.com/jesseduffield/gocui@awesome && go mod vendor
|
GOPROXY=direct go get -u github.com/jesseduffield/gocui@awesome && go mod vendor && go mod tidy
|
||||||
|
|
||||||
# Note to self if you ever want to fork a repo be sure to use this same approach: it's important to use the branch name (e.g. master)
|
# Note to self if you ever want to fork a repo be sure to use this same approach: it's important to use the branch name (e.g. master)
|
||||||
|
4
go.mod
4
go.mod
@ -20,7 +20,7 @@ require (
|
|||||||
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/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.20211031223253-24baf341da75
|
github.com/jesseduffield/gocui v0.3.1-0.20211102081536-e4eee64f4d13
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||||
github.com/jesseduffield/yaml v2.1.0+incompatible
|
github.com/jesseduffield/yaml v2.1.0+incompatible
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||||
@ -40,7 +40,7 @@ require (
|
|||||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
|
||||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
|
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
|
||||||
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect
|
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect
|
||||||
golang.org/x/sys v0.0.0-20211031064116-611d5d643895 // indirect
|
golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c // indirect
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0
|
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0
|
||||||
|
8
go.sum
8
go.sum
@ -71,8 +71,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
|
|||||||
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/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.20211031223253-24baf341da75 h1:zu+WBGwscCwu7GEuxANGl8E51HbW6ueqTF1XdAoqnZs=
|
github.com/jesseduffield/gocui v0.3.1-0.20211102081536-e4eee64f4d13 h1:JB1nYX2l3s9aBtw4Ymc7KXp/Hk3IukO4u+APok6WWjo=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20211031223253-24baf341da75/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
|
github.com/jesseduffield/gocui v0.3.1-0.20211102081536-e4eee64f4d13/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
|
||||||
github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE=
|
github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE=
|
||||||
@ -178,8 +178,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211031064116-611d5d643895 h1:iaNpwpnrgL5jzWS0vCNnfa8HqzxveCFpFx3uC/X4Tps=
|
golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c h1:QOfDMdrf/UwlVR0UBq2Mpr58UzNtvgJRXA4BgPfFACs=
|
||||||
golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
@ -406,7 +406,7 @@ func (c *CommitListBuilder) getLogCmd(opts GetCommitsOptions) *exec.Cmd {
|
|||||||
|
|
||||||
return c.OSCommand.ExecutableFromString(
|
return c.OSCommand.ExecutableFromString(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"git log %s --oneline %s %s --abbrev=%d %s",
|
"git log --topo-order %s --oneline %s %s --abbrev=%d %s",
|
||||||
c.OSCommand.Quote(opts.RefName),
|
c.OSCommand.Quote(opts.RefName),
|
||||||
prettyFormat,
|
prettyFormat,
|
||||||
limitFlag,
|
limitFlag,
|
||||||
|
@ -10,6 +10,9 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// after selecting the 200th commit, we'll load in all the rest
|
||||||
|
const COMMIT_THRESHOLD = 200
|
||||||
|
|
||||||
// list panel functions
|
// list panel functions
|
||||||
|
|
||||||
func (gui *Gui) getSelectedLocalCommit() *models.Commit {
|
func (gui *Gui) getSelectedLocalCommit() *models.Commit {
|
||||||
@ -23,7 +26,7 @@ func (gui *Gui) getSelectedLocalCommit() *models.Commit {
|
|||||||
|
|
||||||
func (gui *Gui) handleCommitSelect() error {
|
func (gui *Gui) handleCommitSelect() error {
|
||||||
state := gui.State.Panels.Commits
|
state := gui.State.Panels.Commits
|
||||||
if state.SelectedLineIdx > 290 && state.LimitCommits {
|
if state.SelectedLineIdx > COMMIT_THRESHOLD && state.LimitCommits {
|
||||||
state.LimitCommits = false
|
state.LimitCommits = false
|
||||||
go utils.Safe(func() {
|
go utils.Safe(func() {
|
||||||
if err := gui.refreshCommitsWithLimit(); err != nil {
|
if err := gui.refreshCommitsWithLimit(); err != nil {
|
||||||
|
@ -395,7 +395,7 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) {
|
|||||||
Remotes: &remotePanelState{listPanelState{SelectedLineIdx: 0}},
|
Remotes: &remotePanelState{listPanelState{SelectedLineIdx: 0}},
|
||||||
RemoteBranches: &remoteBranchesState{listPanelState{SelectedLineIdx: -1}},
|
RemoteBranches: &remoteBranchesState{listPanelState{SelectedLineIdx: -1}},
|
||||||
Tags: &tagsPanelState{listPanelState{SelectedLineIdx: -1}},
|
Tags: &tagsPanelState{listPanelState{SelectedLineIdx: -1}},
|
||||||
Commits: &commitPanelState{listPanelState: listPanelState{SelectedLineIdx: -1}, LimitCommits: true},
|
Commits: &commitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, LimitCommits: true},
|
||||||
ReflogCommits: &reflogCommitPanelState{listPanelState{SelectedLineIdx: 0}},
|
ReflogCommits: &reflogCommitPanelState{listPanelState{SelectedLineIdx: 0}},
|
||||||
SubCommits: &subCommitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, refName: ""},
|
SubCommits: &subCommitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, refName: ""},
|
||||||
CommitFiles: &commitFilesPanelState{listPanelState: listPanelState{SelectedLineIdx: -1}, refName: ""},
|
CommitFiles: &commitFilesPanelState{listPanelState: listPanelState{SelectedLineIdx: -1}, refName: ""},
|
||||||
|
@ -14,6 +14,10 @@ type ListContext struct {
|
|||||||
// the boolean here tells us whether the item is nil. This is needed because you can't work it out on the calling end once the pointer is wrapped in an interface (unless you want to use reflection)
|
// the boolean here tells us whether the item is nil. This is needed because you can't work it out on the calling end once the pointer is wrapped in an interface (unless you want to use reflection)
|
||||||
SelectedItem func() (ListItem, bool)
|
SelectedItem func() (ListItem, bool)
|
||||||
OnGetPanelState func() IListPanelState
|
OnGetPanelState func() IListPanelState
|
||||||
|
// if this is true, we'll call GetDisplayStrings for just the visible part of the
|
||||||
|
// view and re-render that. This is useful when you need to render different
|
||||||
|
// content based on the selection (e.g. for showing the selected commit)
|
||||||
|
RenderSelection bool
|
||||||
|
|
||||||
Gui *Gui
|
Gui *Gui
|
||||||
|
|
||||||
@ -60,10 +64,17 @@ type ListItem interface {
|
|||||||
func (self *ListContext) FocusLine() {
|
func (self *ListContext) FocusLine() {
|
||||||
view, err := self.Gui.g.View(self.ViewName)
|
view, err := self.Gui.g.View(self.ViewName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// ignoring error for now
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we need a way of knowing whether we've rendered to the view yet.
|
||||||
view.FocusPoint(0, self.GetPanelState().GetSelectedLineIdx())
|
view.FocusPoint(0, self.GetPanelState().GetSelectedLineIdx())
|
||||||
|
if self.RenderSelection {
|
||||||
|
_, originY := view.Origin()
|
||||||
|
displayStrings := self.GetDisplayStrings(originY, view.InnerHeight())
|
||||||
|
self.Gui.renderDisplayStringsAtPos(view, originY, displayStrings)
|
||||||
|
}
|
||||||
view.Footer = formatListFooter(self.GetPanelState().GetSelectedLineIdx(), self.GetItemsLength())
|
view.Footer = formatListFooter(self.GetPanelState().GetSelectedLineIdx(), self.GetItemsLength())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,18 +157,29 @@ func (gui *Gui) branchCommitsListContext() IListContext {
|
|||||||
OnClickSelectedItem: gui.handleViewCommitFiles,
|
OnClickSelectedItem: gui.handleViewCommitFiles,
|
||||||
Gui: gui,
|
Gui: gui,
|
||||||
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
||||||
|
selectedCommitSha := ""
|
||||||
|
if gui.currentContext().GetKey() == BRANCH_COMMITS_CONTEXT_KEY {
|
||||||
|
selectedCommit := gui.getSelectedLocalCommit()
|
||||||
|
if selectedCommit != nil {
|
||||||
|
selectedCommitSha = selectedCommit.Sha
|
||||||
|
}
|
||||||
|
}
|
||||||
return presentation.GetCommitListDisplayStrings(
|
return presentation.GetCommitListDisplayStrings(
|
||||||
gui.State.Commits,
|
gui.State.Commits,
|
||||||
gui.State.ScreenMode != SCREEN_NORMAL,
|
gui.State.ScreenMode != SCREEN_NORMAL,
|
||||||
gui.cherryPickedCommitShaMap(),
|
gui.cherryPickedCommitShaMap(),
|
||||||
gui.State.Modes.Diffing.Ref,
|
gui.State.Modes.Diffing.Ref,
|
||||||
parseEmoji,
|
parseEmoji,
|
||||||
|
selectedCommitSha,
|
||||||
|
startIdx,
|
||||||
|
length,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (ListItem, bool) {
|
SelectedItem: func() (ListItem, bool) {
|
||||||
item := gui.getSelectedLocalCommit()
|
item := gui.getSelectedLocalCommit()
|
||||||
return item, item != nil
|
return item, item != nil
|
||||||
},
|
},
|
||||||
|
RenderSelection: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,18 +226,29 @@ func (gui *Gui) subCommitsListContext() IListContext {
|
|||||||
OnFocus: gui.handleSubCommitSelect,
|
OnFocus: gui.handleSubCommitSelect,
|
||||||
Gui: gui,
|
Gui: gui,
|
||||||
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
GetDisplayStrings: func(startIdx int, length int) [][]string {
|
||||||
|
selectedCommitSha := ""
|
||||||
|
if gui.currentContext().GetKey() == SUB_COMMITS_CONTEXT_KEY {
|
||||||
|
selectedCommit := gui.getSelectedSubCommit()
|
||||||
|
if selectedCommit != nil {
|
||||||
|
selectedCommitSha = selectedCommit.Sha
|
||||||
|
}
|
||||||
|
}
|
||||||
return presentation.GetCommitListDisplayStrings(
|
return presentation.GetCommitListDisplayStrings(
|
||||||
gui.State.SubCommits,
|
gui.State.SubCommits,
|
||||||
gui.State.ScreenMode != SCREEN_NORMAL,
|
gui.State.ScreenMode != SCREEN_NORMAL,
|
||||||
gui.cherryPickedCommitShaMap(),
|
gui.cherryPickedCommitShaMap(),
|
||||||
gui.State.Modes.Diffing.Ref,
|
gui.State.Modes.Diffing.Ref,
|
||||||
parseEmoji,
|
parseEmoji,
|
||||||
|
selectedCommitSha,
|
||||||
|
0,
|
||||||
|
len(gui.State.SubCommits),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
SelectedItem: func() (ListItem, bool) {
|
SelectedItem: func() (ListItem, bool) {
|
||||||
item := gui.getSelectedSubCommit()
|
item := gui.getSelectedSubCommit()
|
||||||
return item, item != nil
|
return item, item != nil
|
||||||
},
|
},
|
||||||
|
RenderSelection: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,120 +2,152 @@ package presentation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation/authors"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/authors"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/graph"
|
||||||
"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/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/kyokomi/emoji/v2"
|
"github.com/kyokomi/emoji/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaMap map[string]bool, diffName string, parseEmoji bool) [][]string {
|
type pipeSetCacheKey struct {
|
||||||
lines := make([][]string, len(commits))
|
commitSha string
|
||||||
|
commitCount int
|
||||||
|
}
|
||||||
|
|
||||||
var displayFunc func(*models.Commit, map[string]bool, bool, bool) []string
|
var pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe)
|
||||||
if fullDescription {
|
var mutex sync.Mutex
|
||||||
displayFunc = getFullDescriptionDisplayStringsForCommit
|
|
||||||
} else {
|
func GetCommitListDisplayStrings(
|
||||||
displayFunc = getDisplayStringsForCommit
|
commits []*models.Commit,
|
||||||
|
fullDescription bool,
|
||||||
|
cherryPickedCommitShaMap map[string]bool,
|
||||||
|
diffName string,
|
||||||
|
parseEmoji bool,
|
||||||
|
selectedCommitSha string,
|
||||||
|
startIdx int,
|
||||||
|
length int,
|
||||||
|
) [][]string {
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
|
||||||
|
if len(commits) == 0 {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range commits {
|
// given that our cache key is a commit sha and a commit count, it's very important that we don't actually try to render pipes
|
||||||
diffed := commits[i].Sha == diffName
|
// when dealing with things like filtered commits.
|
||||||
lines[i] = displayFunc(commits[i], cherryPickedCommitShaMap, diffed, parseEmoji)
|
cacheKey := pipeSetCacheKey{
|
||||||
|
commitSha: commits[0].Sha,
|
||||||
|
commitCount: len(commits),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pipeSets, ok := pipeSetCache[cacheKey]
|
||||||
|
if !ok {
|
||||||
|
// pipe sets are unique to a commit head. and a commit count. Sometimes we haven't loaded everything for that.
|
||||||
|
// so let's just cache it based on that.
|
||||||
|
getStyle := func(commit *models.Commit) style.TextStyle {
|
||||||
|
return authors.AuthorStyle(commit.Author)
|
||||||
|
}
|
||||||
|
pipeSets = graph.GetPipeSets(commits, getStyle)
|
||||||
|
pipeSetCache[cacheKey] = pipeSets
|
||||||
|
}
|
||||||
|
|
||||||
|
end := startIdx + length
|
||||||
|
if end > len(commits)-1 {
|
||||||
|
end = len(commits) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredPipeSets := pipeSets[startIdx : end+1]
|
||||||
|
filteredCommits := commits[startIdx : end+1]
|
||||||
|
graphLines := graph.RenderAux(filteredPipeSets, filteredCommits, selectedCommitSha)
|
||||||
|
|
||||||
|
lines := make([][]string, 0, len(graphLines))
|
||||||
|
for i, commit := range filteredCommits {
|
||||||
|
lines = append(lines, displayCommit(commit, cherryPickedCommitShaMap, diffName, parseEmoji, graphLines[i], fullDescription))
|
||||||
|
}
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFullDescriptionDisplayStringsForCommit(c *models.Commit, cherryPickedCommitShaMap map[string]bool, diffed, parseEmoji bool) []string {
|
func displayCommit(
|
||||||
shaColor := theme.DefaultTextColor
|
commit *models.Commit,
|
||||||
switch c.Status {
|
cherryPickedCommitShaMap map[string]bool,
|
||||||
case "unpushed":
|
diffName string,
|
||||||
shaColor = style.FgRed
|
parseEmoji bool,
|
||||||
case "pushed":
|
graphLine string,
|
||||||
shaColor = style.FgYellow
|
fullDescription bool,
|
||||||
case "merged":
|
) []string {
|
||||||
shaColor = style.FgGreen
|
|
||||||
case "rebasing":
|
|
||||||
shaColor = style.FgBlue
|
|
||||||
case "reflog":
|
|
||||||
shaColor = style.FgBlue
|
|
||||||
}
|
|
||||||
|
|
||||||
if diffed {
|
shaColor := getShaColor(commit, diffName, cherryPickedCommitShaMap)
|
||||||
shaColor = theme.DiffTerminalColor
|
|
||||||
} else if cherryPickedCommitShaMap[c.Sha] {
|
|
||||||
// for some reason, setting the background to blue pads out the other commits
|
|
||||||
// horizontally. For the sake of accessibility I'm considering this a feature,
|
|
||||||
// not a bug
|
|
||||||
shaColor = theme.CherryPickedCommitTextStyle
|
|
||||||
}
|
|
||||||
|
|
||||||
tagString := ""
|
|
||||||
secondColumnString := style.FgBlue.Sprint(utils.UnixToDate(c.UnixTimestamp))
|
|
||||||
if c.Action != "" {
|
|
||||||
secondColumnString = actionColorMap(c.Action).Sprint(c.Action)
|
|
||||||
} else if c.ExtraInfo != "" {
|
|
||||||
tagString = style.FgMagenta.SetBold().Sprint(c.ExtraInfo) + " "
|
|
||||||
}
|
|
||||||
|
|
||||||
name := c.Name
|
|
||||||
if parseEmoji {
|
|
||||||
name = emoji.Sprint(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return []string{
|
|
||||||
shaColor.Sprint(c.ShortSha()),
|
|
||||||
secondColumnString,
|
|
||||||
authors.LongAuthor(c.Author),
|
|
||||||
tagString + theme.DefaultTextColor.Sprint(name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDisplayStringsForCommit(c *models.Commit, cherryPickedCommitShaMap map[string]bool, diffed, parseEmoji bool) []string {
|
|
||||||
shaColor := theme.DefaultTextColor
|
|
||||||
switch c.Status {
|
|
||||||
case "unpushed":
|
|
||||||
shaColor = style.FgRed
|
|
||||||
case "pushed":
|
|
||||||
shaColor = style.FgYellow
|
|
||||||
case "merged":
|
|
||||||
shaColor = style.FgGreen
|
|
||||||
case "rebasing":
|
|
||||||
shaColor = style.FgBlue
|
|
||||||
case "reflog":
|
|
||||||
shaColor = style.FgBlue
|
|
||||||
}
|
|
||||||
|
|
||||||
if diffed {
|
|
||||||
shaColor = theme.DiffTerminalColor
|
|
||||||
} else if cherryPickedCommitShaMap[c.Sha] {
|
|
||||||
// for some reason, setting the background to blue pads out the other commits
|
|
||||||
// horizontally. For the sake of accessibility I'm considering this a feature,
|
|
||||||
// not a bug
|
|
||||||
shaColor = theme.CherryPickedCommitTextStyle
|
|
||||||
}
|
|
||||||
|
|
||||||
actionString := ""
|
actionString := ""
|
||||||
tagString := ""
|
if commit.Action != "" {
|
||||||
if c.Action != "" {
|
actionString = actionColorMap(commit.Action).Sprint(commit.Action) + " "
|
||||||
actionString = actionColorMap(c.Action).Sprint(utils.WithPadding(c.Action, 7)) + " "
|
|
||||||
} else if len(c.Tags) > 0 {
|
|
||||||
tagString = theme.DiffTerminalColor.SetBold().Sprint(strings.Join(c.Tags, " ")) + " "
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name := c.Name
|
tagString := ""
|
||||||
|
if fullDescription {
|
||||||
|
if commit.ExtraInfo != "" {
|
||||||
|
tagString = style.FgMagenta.SetBold().Sprint(commit.ExtraInfo) + " "
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(commit.Tags) > 0 {
|
||||||
|
tagString = theme.DiffTerminalColor.SetBold().Sprint(strings.Join(commit.Tags, " ")) + " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := commit.Name
|
||||||
if parseEmoji {
|
if parseEmoji {
|
||||||
name = emoji.Sprint(name)
|
name = emoji.Sprint(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{
|
authorFunc := authors.ShortAuthor
|
||||||
shaColor.Sprint(c.ShortSha()),
|
if fullDescription {
|
||||||
authors.ShortAuthor(c.Author),
|
authorFunc = authors.LongAuthor
|
||||||
actionString + tagString + theme.DefaultTextColor.Sprint(name),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cols := make([]string, 0, 5)
|
||||||
|
cols = append(cols, shaColor.Sprint(commit.ShortSha()))
|
||||||
|
if fullDescription {
|
||||||
|
cols = append(cols, style.FgBlue.Sprint(utils.UnixToDate(commit.UnixTimestamp)))
|
||||||
|
}
|
||||||
|
cols = append(
|
||||||
|
cols,
|
||||||
|
actionString,
|
||||||
|
authorFunc(commit.Author),
|
||||||
|
graphLine+tagString+theme.DefaultTextColor.Sprint(name),
|
||||||
|
)
|
||||||
|
|
||||||
|
return cols
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func getShaColor(commit *models.Commit, diffName string, cherryPickedCommitShaMap map[string]bool) style.TextStyle {
|
||||||
|
diffed := commit.Sha == diffName
|
||||||
|
shaColor := theme.DefaultTextColor
|
||||||
|
switch commit.Status {
|
||||||
|
case "unpushed":
|
||||||
|
shaColor = style.FgRed
|
||||||
|
case "pushed":
|
||||||
|
shaColor = style.FgYellow
|
||||||
|
case "merged":
|
||||||
|
shaColor = style.FgGreen
|
||||||
|
case "rebasing":
|
||||||
|
shaColor = style.FgBlue
|
||||||
|
case "reflog":
|
||||||
|
shaColor = style.FgBlue
|
||||||
|
}
|
||||||
|
|
||||||
|
if diffed {
|
||||||
|
shaColor = theme.DiffTerminalColor
|
||||||
|
} else if cherryPickedCommitShaMap[commit.Sha] {
|
||||||
|
shaColor = theme.CherryPickedCommitTextStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
return shaColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func actionColorMap(str string) style.TextStyle {
|
func actionColorMap(str string) style.TextStyle {
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package graph
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gookit/color"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
)
|
)
|
||||||
|
|
||||||
const mergeSymbol = '⏣'
|
const mergeSymbol = "⏣"
|
||||||
const commitSymbol = '⎔'
|
const commitSymbol = "⎔"
|
||||||
|
|
||||||
type cellType int
|
type cellType int
|
||||||
|
|
||||||
@ -22,11 +26,11 @@ type Cell struct {
|
|||||||
style style.TextStyle
|
style style.TextStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *Cell) render() string {
|
func (cell *Cell) render(writer io.StringWriter) {
|
||||||
up, down, left, right := cell.up, cell.down, cell.left, cell.right
|
up, down, left, right := cell.up, cell.down, cell.left, cell.right
|
||||||
|
|
||||||
first, second := getBoxDrawingChars(up, down, left, right)
|
first, second := getBoxDrawingChars(up, down, left, right)
|
||||||
var adjustedFirst rune
|
var adjustedFirst string
|
||||||
switch cell.cellType {
|
switch cell.cellType {
|
||||||
case CONNECTION:
|
case CONNECTION:
|
||||||
adjustedFirst = first
|
adjustedFirst = first
|
||||||
@ -47,13 +51,46 @@ func (cell *Cell) render() string {
|
|||||||
// assert on the style of a space given a space has no styling (assuming we
|
// assert on the style of a space given a space has no styling (assuming we
|
||||||
// stick to only using foreground styles)
|
// stick to only using foreground styles)
|
||||||
var styledSecondChar string
|
var styledSecondChar string
|
||||||
if second == ' ' {
|
if second == " " {
|
||||||
styledSecondChar = " "
|
styledSecondChar = " "
|
||||||
} else {
|
} else {
|
||||||
styledSecondChar = rightStyle.Sprint(string(second))
|
styledSecondChar = cachedSprint(*rightStyle, second)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cell.style.Sprint(string(adjustedFirst)) + styledSecondChar
|
_, _ = writer.WriteString(cachedSprint(cell.style, adjustedFirst))
|
||||||
|
_, _ = writer.WriteString(styledSecondChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
type rgbCacheKey struct {
|
||||||
|
*color.RGBStyle
|
||||||
|
str string
|
||||||
|
}
|
||||||
|
|
||||||
|
var rgbCache = make(map[rgbCacheKey]string)
|
||||||
|
var rgbCacheMutex sync.RWMutex
|
||||||
|
|
||||||
|
func cachedSprint(style style.TextStyle, str string) string {
|
||||||
|
switch v := style.Style.(type) {
|
||||||
|
case *color.RGBStyle:
|
||||||
|
rgbCacheMutex.RLock()
|
||||||
|
key := rgbCacheKey{v, str}
|
||||||
|
value, ok := rgbCache[key]
|
||||||
|
rgbCacheMutex.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
value = style.Sprint(str)
|
||||||
|
rgbCacheMutex.Lock()
|
||||||
|
rgbCache[key] = value
|
||||||
|
rgbCacheMutex.Unlock()
|
||||||
|
return value
|
||||||
|
case color.Basic:
|
||||||
|
return style.Sprint(str)
|
||||||
|
case color.Style:
|
||||||
|
value := style.Sprint(str)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return style.Sprint(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *Cell) reset() {
|
func (cell *Cell) reset() {
|
||||||
@ -102,39 +139,39 @@ func (cell *Cell) setType(cellType cellType) *Cell {
|
|||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBoxDrawingChars(up, down, left, right bool) (rune, rune) {
|
func getBoxDrawingChars(up, down, left, right bool) (string, string) {
|
||||||
if up && down && left && right {
|
if up && down && left && right {
|
||||||
return '│', '─'
|
return "│", "─"
|
||||||
} else if up && down && left && !right {
|
} else if up && down && left && !right {
|
||||||
return '│', ' '
|
return "│", " "
|
||||||
} else if up && down && !left && right {
|
} else if up && down && !left && right {
|
||||||
return '│', '─'
|
return "│", "─"
|
||||||
} else if up && down && !left && !right {
|
} else if up && down && !left && !right {
|
||||||
return '│', ' '
|
return "│", " "
|
||||||
} else if up && !down && left && right {
|
} else if up && !down && left && right {
|
||||||
return '┴', '─'
|
return "┴", "─"
|
||||||
} else if up && !down && left && !right {
|
} else if up && !down && left && !right {
|
||||||
return '╯', ' '
|
return "╯", " "
|
||||||
} else if up && !down && !left && right {
|
} else if up && !down && !left && right {
|
||||||
return '╰', '─'
|
return "╰", "─"
|
||||||
} else if up && !down && !left && !right {
|
} else if up && !down && !left && !right {
|
||||||
return '╵', ' '
|
return "╵", " "
|
||||||
} else if !up && down && left && right {
|
} else if !up && down && left && right {
|
||||||
return '┬', '─'
|
return "┬", "─"
|
||||||
} else if !up && down && left && !right {
|
} else if !up && down && left && !right {
|
||||||
return '╮', ' '
|
return "╮", " "
|
||||||
} else if !up && down && !left && right {
|
} else if !up && down && !left && right {
|
||||||
return '╭', '─'
|
return "╭", "─"
|
||||||
} else if !up && down && !left && !right {
|
} else if !up && down && !left && !right {
|
||||||
return '╷', ' '
|
return "╷", " "
|
||||||
} else if !up && !down && left && right {
|
} else if !up && !down && left && right {
|
||||||
return '─', '─'
|
return "─", "─"
|
||||||
} else if !up && !down && left && !right {
|
} else if !up && !down && left && !right {
|
||||||
return '─', ' '
|
return "─", " "
|
||||||
} else if !up && !down && !left && right {
|
} else if !up && !down && !left && right {
|
||||||
return '╶', '─'
|
return "╶", "─"
|
||||||
} else if !up && !down && !left && !right {
|
} else if !up && !down && !left && !right {
|
||||||
return ' ', ' '
|
return " ", " "
|
||||||
} else {
|
} else {
|
||||||
panic("should not be possible")
|
panic("should not be possible")
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package graph
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -29,7 +30,7 @@ type Pipe struct {
|
|||||||
|
|
||||||
var highlightStyle = style.FgLightWhite.SetBold()
|
var highlightStyle = style.FgLightWhite.SetBold()
|
||||||
|
|
||||||
func ContainsCommitSha(pipes []Pipe, sha string) bool {
|
func ContainsCommitSha(pipes []*Pipe, sha string) bool {
|
||||||
for _, pipe := range pipes {
|
for _, pipe := range pipes {
|
||||||
if equalHashes(pipe.fromSha, sha) {
|
if equalHashes(pipe.fromSha, sha) {
|
||||||
return true
|
return true
|
||||||
@ -57,14 +58,14 @@ func RenderCommitGraph(commits []*models.Commit, selectedCommitSha string, getSt
|
|||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPipeSets(commits []*models.Commit, getStyle func(c *models.Commit) style.TextStyle) [][]Pipe {
|
func GetPipeSets(commits []*models.Commit, getStyle func(c *models.Commit) style.TextStyle) [][]*Pipe {
|
||||||
if len(commits) == 0 {
|
if len(commits) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pipes := []Pipe{{fromPos: 0, toPos: 0, fromSha: "START", toSha: commits[0].Sha, kind: STARTS, style: style.FgDefault}}
|
pipes := []*Pipe{{fromPos: 0, toPos: 0, fromSha: "START", toSha: commits[0].Sha, kind: STARTS, style: style.FgDefault}}
|
||||||
|
|
||||||
pipeSets := [][]Pipe{}
|
pipeSets := [][]*Pipe{}
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
pipes = getNextPipes(pipes, commit, getStyle)
|
pipes = getNextPipes(pipes, commit, getStyle)
|
||||||
pipeSets = append(pipeSets, pipes)
|
pipeSets = append(pipeSets, pipes)
|
||||||
@ -73,29 +74,51 @@ func GetPipeSets(commits []*models.Commit, getStyle func(c *models.Commit) style
|
|||||||
return pipeSets
|
return pipeSets
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenderAux(pipeSets [][]Pipe, commits []*models.Commit, selectedCommitSha string) []string {
|
func RenderAux(pipeSets [][]*Pipe, commits []*models.Commit, selectedCommitSha string) []string {
|
||||||
lines := make([]string, len(pipeSets))
|
maxProcs := runtime.GOMAXPROCS(0)
|
||||||
|
|
||||||
|
lines := make([]string, 0, len(pipeSets))
|
||||||
|
// splitting up the rendering of the graph into multiple goroutines allows us to render the graph in parallel
|
||||||
|
chunks := make([][]string, maxProcs)
|
||||||
|
perProc := len(pipeSets) / maxProcs
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(pipeSets))
|
wg.Add(maxProcs)
|
||||||
for i, pipeSet := range pipeSets {
|
|
||||||
|
for i := 0; i < maxProcs; i++ {
|
||||||
i := i
|
i := i
|
||||||
pipeSet := pipeSet
|
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
from := i * perProc
|
||||||
var prevCommit *models.Commit
|
to := (i + 1) * perProc
|
||||||
if i > 0 {
|
if i == maxProcs-1 {
|
||||||
prevCommit = commits[i-1]
|
to = len(pipeSets)
|
||||||
}
|
}
|
||||||
line := renderPipeSet(pipeSet, selectedCommitSha, prevCommit)
|
innerLines := make([]string, 0, to-from)
|
||||||
lines[i] = line
|
for j, pipeSet := range pipeSets[from:to] {
|
||||||
|
k := from + j
|
||||||
|
var prevCommit *models.Commit
|
||||||
|
if k > 0 {
|
||||||
|
prevCommit = commits[k-1]
|
||||||
|
}
|
||||||
|
line := renderPipeSet(pipeSet, selectedCommitSha, prevCommit)
|
||||||
|
innerLines = append(innerLines, line)
|
||||||
|
}
|
||||||
|
chunks[i] = innerLines
|
||||||
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
lines = append(lines, chunk...)
|
||||||
|
}
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *models.Commit) style.TextStyle) []Pipe {
|
func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *models.Commit) style.TextStyle) []*Pipe {
|
||||||
currentPipes := make([]Pipe, 0, len(prevPipes))
|
currentPipes := make([]*Pipe, 0, len(prevPipes))
|
||||||
maxPos := 0
|
maxPos := 0
|
||||||
for _, pipe := range prevPipes {
|
for _, pipe := range prevPipes {
|
||||||
// a pipe that terminated in the previous line has no bearing on the current line
|
// a pipe that terminated in the previous line has no bearing on the current line
|
||||||
@ -106,7 +129,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||||||
maxPos = utils.Max(maxPos, pipe.toPos)
|
maxPos = utils.Max(maxPos, pipe.toPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
newPipes := make([]Pipe, 0, len(currentPipes)+len(commit.Parents))
|
newPipes := make([]*Pipe, 0, len(currentPipes)+len(commit.Parents))
|
||||||
// start by assuming that we've got a brand new commit not related to any preceding commit.
|
// start by assuming that we've got a brand new commit not related to any preceding commit.
|
||||||
// (this only happens when we're doing `git log --all`). These will be tacked onto the far end.
|
// (this only happens when we're doing `git log --all`). These will be tacked onto the far end.
|
||||||
pos := maxPos + 1
|
pos := maxPos + 1
|
||||||
@ -124,7 +147,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||||||
traversedSpots := make(map[int]bool)
|
traversedSpots := make(map[int]bool)
|
||||||
|
|
||||||
if len(commit.Parents) > 0 {
|
if len(commit.Parents) > 0 {
|
||||||
newPipes = append(newPipes, Pipe{
|
newPipes = append(newPipes, &Pipe{
|
||||||
fromPos: pos,
|
fromPos: pos,
|
||||||
toPos: pos,
|
toPos: pos,
|
||||||
fromSha: commit.Sha,
|
fromSha: commit.Sha,
|
||||||
@ -177,7 +200,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||||||
for _, pipe := range currentPipes {
|
for _, pipe := range currentPipes {
|
||||||
if equalHashes(pipe.toSha, commit.Sha) {
|
if equalHashes(pipe.toSha, commit.Sha) {
|
||||||
// terminating here
|
// terminating here
|
||||||
newPipes = append(newPipes, Pipe{
|
newPipes = append(newPipes, &Pipe{
|
||||||
fromPos: pipe.toPos,
|
fromPos: pipe.toPos,
|
||||||
toPos: pos,
|
toPos: pos,
|
||||||
fromSha: pipe.fromSha,
|
fromSha: pipe.fromSha,
|
||||||
@ -189,7 +212,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||||||
} else if pipe.toPos < pos {
|
} else if pipe.toPos < pos {
|
||||||
// continuing here
|
// continuing here
|
||||||
availablePos := getNextAvailablePosForContinuingPipe()
|
availablePos := getNextAvailablePosForContinuingPipe()
|
||||||
newPipes = append(newPipes, Pipe{
|
newPipes = append(newPipes, &Pipe{
|
||||||
fromPos: pipe.toPos,
|
fromPos: pipe.toPos,
|
||||||
toPos: availablePos,
|
toPos: availablePos,
|
||||||
fromSha: pipe.fromSha,
|
fromSha: pipe.fromSha,
|
||||||
@ -205,7 +228,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||||||
for _, parent := range commit.Parents[1:] {
|
for _, parent := range commit.Parents[1:] {
|
||||||
availablePos := getNextAvailablePosForNewPipe()
|
availablePos := getNextAvailablePosForNewPipe()
|
||||||
// need to act as if continuing pipes are going to continue on the same line.
|
// need to act as if continuing pipes are going to continue on the same line.
|
||||||
newPipes = append(newPipes, Pipe{
|
newPipes = append(newPipes, &Pipe{
|
||||||
fromPos: pos,
|
fromPos: pos,
|
||||||
toPos: availablePos,
|
toPos: availablePos,
|
||||||
fromSha: commit.Sha,
|
fromSha: commit.Sha,
|
||||||
@ -229,7 +252,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||||||
last = i
|
last = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newPipes = append(newPipes, Pipe{
|
newPipes = append(newPipes, &Pipe{
|
||||||
fromPos: pipe.toPos,
|
fromPos: pipe.toPos,
|
||||||
toPos: last,
|
toPos: last,
|
||||||
fromSha: pipe.fromSha,
|
fromSha: pipe.fromSha,
|
||||||
@ -253,7 +276,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
func renderPipeSet(
|
func renderPipeSet(
|
||||||
pipes []Pipe,
|
pipes []*Pipe,
|
||||||
selectedCommitSha string,
|
selectedCommitSha string,
|
||||||
prevCommit *models.Commit,
|
prevCommit *models.Commit,
|
||||||
) string {
|
) string {
|
||||||
@ -279,7 +302,7 @@ func renderPipeSet(
|
|||||||
cells[i] = &Cell{cellType: CONNECTION, style: style.FgDefault}
|
cells[i] = &Cell{cellType: CONNECTION, style: style.FgDefault}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPipe := func(pipe Pipe, style style.TextStyle, overrideRightStyle bool) {
|
renderPipe := func(pipe *Pipe, style style.TextStyle, overrideRightStyle bool) {
|
||||||
left := pipe.left()
|
left := pipe.left()
|
||||||
right := pipe.right()
|
right := pipe.right()
|
||||||
|
|
||||||
@ -313,9 +336,9 @@ func renderPipeSet(
|
|||||||
|
|
||||||
// so we have our commit pos again, now it's time to build the cells.
|
// so we have our commit pos again, now it's time to build the cells.
|
||||||
// we'll handle the one that's sourced from our selected commit last so that it can override the other cells.
|
// we'll handle the one that's sourced from our selected commit last so that it can override the other cells.
|
||||||
selectedPipes := []Pipe{}
|
selectedPipes := []*Pipe{}
|
||||||
// pre-allocating this one because most of the time we'll only have non-selected pipes
|
// pre-allocating this one because most of the time we'll only have non-selected pipes
|
||||||
nonSelectedPipes := make([]Pipe, 0, len(pipes))
|
nonSelectedPipes := make([]*Pipe, 0, len(pipes))
|
||||||
|
|
||||||
for _, pipe := range pipes {
|
for _, pipe := range pipes {
|
||||||
if highlight && equalHashes(pipe.fromSha, selectedCommitSha) {
|
if highlight && equalHashes(pipe.fromSha, selectedCommitSha) {
|
||||||
@ -356,11 +379,13 @@ func renderPipeSet(
|
|||||||
|
|
||||||
cells[commitPos].setType(cType)
|
cells[commitPos].setType(cType)
|
||||||
|
|
||||||
renderedCells := make([]string, len(cells))
|
// using a string builder here for the sake of performance
|
||||||
for i, cell := range cells {
|
writer := &strings.Builder{}
|
||||||
renderedCells[i] = cell.render()
|
writer.Grow(len(cells) * 2)
|
||||||
|
for _, cell := range cells {
|
||||||
|
cell.render(writer)
|
||||||
}
|
}
|
||||||
return strings.Join(renderedCells, "")
|
return writer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func equalHashes(a, b string) bool {
|
func equalHashes(a, b string) bool {
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package graph
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gookit/color"
|
"github.com/gookit/color"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/authors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -253,7 +256,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
pipes []Pipe
|
pipes []*Pipe
|
||||||
commit *models.Commit
|
commit *models.Commit
|
||||||
prevCommit *models.Commit
|
prevCommit *models.Commit
|
||||||
expectedStr string
|
expectedStr string
|
||||||
@ -261,7 +264,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "single cell",
|
name: "single cell",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: cyan},
|
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: cyan},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: STARTS, style: green},
|
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: STARTS, style: green},
|
||||||
},
|
},
|
||||||
@ -271,7 +274,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "single cell, selected",
|
name: "single cell, selected",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "selected", kind: TERMINATES, style: cyan},
|
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "selected", kind: TERMINATES, style: cyan},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "c", kind: STARTS, style: green},
|
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "c", kind: STARTS, style: green},
|
||||||
},
|
},
|
||||||
@ -281,7 +284,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "terminating hook and starting hook, selected",
|
name: "terminating hook and starting hook, selected",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "selected", kind: TERMINATES, style: cyan},
|
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "selected", kind: TERMINATES, style: cyan},
|
||||||
{fromPos: 1, toPos: 0, fromSha: "c", toSha: "selected", kind: TERMINATES, style: yellow},
|
{fromPos: 1, toPos: 0, fromSha: "c", toSha: "selected", kind: TERMINATES, style: yellow},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "d", kind: STARTS, style: green},
|
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "d", kind: STARTS, style: green},
|
||||||
@ -294,8 +297,8 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "terminating hook and starting hook, prioritise the starting one",
|
name: "terminating hook and starting hook, prioritise the terminating one",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: red},
|
||||||
{fromPos: 1, toPos: 0, fromSha: "c", toSha: "b", kind: TERMINATES, style: magenta},
|
{fromPos: 1, toPos: 0, fromSha: "c", toSha: "b", kind: TERMINATES, style: magenta},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "d", kind: STARTS, style: green},
|
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "d", kind: STARTS, style: green},
|
||||||
@ -309,7 +312,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "starting and terminating pipe sharing some space",
|
name: "starting and terminating pipe sharing some space",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
||||||
{fromPos: 1, toPos: 1, fromSha: "b1", toSha: "b2", kind: CONTINUES, style: magenta},
|
{fromPos: 1, toPos: 1, fromSha: "b1", toSha: "b2", kind: CONTINUES, style: magenta},
|
||||||
@ -324,7 +327,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "starting and terminating pipe sharing some space, with selection",
|
name: "starting and terminating pipe sharing some space, with selection",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "selected", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "selected", kind: TERMINATES, style: red},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "a3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "a3", kind: STARTS, style: yellow},
|
||||||
{fromPos: 1, toPos: 1, fromSha: "b1", toSha: "b2", kind: CONTINUES, style: magenta},
|
{fromPos: 1, toPos: 1, fromSha: "b1", toSha: "b2", kind: CONTINUES, style: magenta},
|
||||||
@ -339,7 +342,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "many terminating pipes",
|
name: "many terminating pipes",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
||||||
{fromPos: 1, toPos: 0, fromSha: "b1", toSha: "a2", kind: TERMINATES, style: magenta},
|
{fromPos: 1, toPos: 0, fromSha: "b1", toSha: "a2", kind: TERMINATES, style: magenta},
|
||||||
@ -353,7 +356,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "starting pipe passing through",
|
name: "starting pipe passing through",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
||||||
{fromPos: 0, toPos: 3, fromSha: "a2", toSha: "d3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 3, fromSha: "a2", toSha: "d3", kind: STARTS, style: yellow},
|
||||||
@ -368,7 +371,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "starting and terminating path crossing continuing path",
|
name: "starting and terminating path crossing continuing path",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
||||||
{fromPos: 0, toPos: 1, fromSha: "a2", toSha: "b3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 1, fromSha: "a2", toSha: "b3", kind: STARTS, style: yellow},
|
||||||
@ -383,7 +386,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "another clash of starting and terminating paths",
|
name: "another clash of starting and terminating paths",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
||||||
{fromPos: 0, toPos: 1, fromSha: "a2", toSha: "b3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 1, fromSha: "a2", toSha: "b3", kind: STARTS, style: yellow},
|
||||||
@ -398,7 +401,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "commit whose previous commit is selected",
|
name: "commit whose previous commit is selected",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
||||||
},
|
},
|
||||||
@ -410,7 +413,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "commit whose previous commit is selected and is a merge commit",
|
name: "commit whose previous commit is selected and is a merge commit",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 1, toPos: 1, fromSha: "selected", toSha: "b3", kind: CONTINUES, style: red},
|
{fromPos: 1, toPos: 1, fromSha: "selected", toSha: "b3", kind: CONTINUES, style: red},
|
||||||
},
|
},
|
||||||
@ -422,7 +425,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "commit whose previous commit is selected and is a merge commit, with continuing pipe inbetween",
|
name: "commit whose previous commit is selected and is a merge commit, with continuing pipe inbetween",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "selected", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 1, toPos: 1, fromSha: "z1", toSha: "z3", kind: CONTINUES, style: green},
|
{fromPos: 1, toPos: 1, fromSha: "z1", toSha: "z3", kind: CONTINUES, style: green},
|
||||||
{fromPos: 2, toPos: 2, fromSha: "selected", toSha: "b3", kind: CONTINUES, style: red},
|
{fromPos: 2, toPos: 2, fromSha: "selected", toSha: "b3", kind: CONTINUES, style: red},
|
||||||
@ -435,7 +438,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when previous commit is selected, not a merge commit, and spawns a continuing pipe",
|
name: "when previous commit is selected, not a merge commit, and spawns a continuing pipe",
|
||||||
pipes: []Pipe{
|
pipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
{fromPos: 0, toPos: 0, fromSha: "a1", toSha: "a2", kind: TERMINATES, style: red},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: green},
|
{fromPos: 0, toPos: 0, fromSha: "a2", toSha: "a3", kind: STARTS, style: green},
|
||||||
{fromPos: 0, toPos: 1, fromSha: "a2", toSha: "b3", kind: STARTS, style: green},
|
{fromPos: 0, toPos: 1, fromSha: "a2", toSha: "b3", kind: STARTS, style: green},
|
||||||
@ -471,57 +474,27 @@ func TestRenderPipeSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCellRender(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
cell *Cell
|
|
||||||
expectedString string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
cell: &Cell{
|
|
||||||
up: true,
|
|
||||||
down: true,
|
|
||||||
cellType: CONNECTION,
|
|
||||||
style: style.FgCyan,
|
|
||||||
},
|
|
||||||
expectedString: "\x1b[36m│\x1b[0m ",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cell: &Cell{
|
|
||||||
up: true,
|
|
||||||
down: true,
|
|
||||||
cellType: COMMIT,
|
|
||||||
style: style.FgCyan,
|
|
||||||
},
|
|
||||||
expectedString: "\x1b[36m⎔\x1b[0m ",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
assert.EqualValues(t, test.expectedString, test.cell.render())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetNextPipes(t *testing.T) {
|
func TestGetNextPipes(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
prevPipes []Pipe
|
prevPipes []*Pipe
|
||||||
commit *models.Commit
|
commit *models.Commit
|
||||||
expected []Pipe
|
expected []*Pipe
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
prevPipes: []Pipe{
|
prevPipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: STARTS, style: style.FgDefault},
|
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: STARTS, style: style.FgDefault},
|
||||||
},
|
},
|
||||||
commit: &models.Commit{
|
commit: &models.Commit{
|
||||||
Sha: "b",
|
Sha: "b",
|
||||||
Parents: []string{"c"},
|
Parents: []string{"c"},
|
||||||
},
|
},
|
||||||
expected: []Pipe{
|
expected: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: style.FgDefault},
|
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: style.FgDefault},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: STARTS, style: style.FgDefault},
|
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: STARTS, style: style.FgDefault},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prevPipes: []Pipe{
|
prevPipes: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: style.FgDefault},
|
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: style.FgDefault},
|
||||||
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: STARTS, style: style.FgDefault},
|
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: STARTS, style: style.FgDefault},
|
||||||
{fromPos: 0, toPos: 1, fromSha: "b", toSha: "d", kind: STARTS, style: style.FgDefault},
|
{fromPos: 0, toPos: 1, fromSha: "b", toSha: "d", kind: STARTS, style: style.FgDefault},
|
||||||
@ -530,7 +503,7 @@ func TestGetNextPipes(t *testing.T) {
|
|||||||
Sha: "d",
|
Sha: "d",
|
||||||
Parents: []string{"e"},
|
Parents: []string{"e"},
|
||||||
},
|
},
|
||||||
expected: []Pipe{
|
expected: []*Pipe{
|
||||||
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: CONTINUES, style: style.FgDefault},
|
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: CONTINUES, style: style.FgDefault},
|
||||||
{fromPos: 1, toPos: 1, fromSha: "b", toSha: "d", kind: TERMINATES, style: style.FgDefault},
|
{fromPos: 1, toPos: 1, fromSha: "b", toSha: "d", kind: TERMINATES, style: style.FgDefault},
|
||||||
{fromPos: 1, toPos: 1, fromSha: "d", toSha: "e", kind: STARTS, style: style.FgDefault},
|
{fromPos: 1, toPos: 1, fromSha: "d", toSha: "e", kind: STARTS, style: style.FgDefault},
|
||||||
@ -551,3 +524,47 @@ func TestGetNextPipes(t *testing.T) {
|
|||||||
assert.EqualValues(t, test.expected, pipes)
|
assert.EqualValues(t, test.expected, pipes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkRenderCommitGraph(b *testing.B) {
|
||||||
|
commits := generateCommits(50)
|
||||||
|
getStyle := func(commit *models.Commit) style.TextStyle {
|
||||||
|
return authors.AuthorStyle(commit.Author)
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
RenderCommitGraph(commits, "selected", getStyle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCommits(count int) []*models.Commit {
|
||||||
|
rand.Seed(1234)
|
||||||
|
pool := []*models.Commit{{Sha: "a", Author: "A"}}
|
||||||
|
commits := make([]*models.Commit, 0, count)
|
||||||
|
authorPool := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
|
||||||
|
for len(commits) < count {
|
||||||
|
currentCommitIdx := rand.Intn(len(pool))
|
||||||
|
currentCommit := pool[currentCommitIdx]
|
||||||
|
pool = append(pool[0:currentCommitIdx], pool[currentCommitIdx+1:]...)
|
||||||
|
// I need to pick a random number of parents to add
|
||||||
|
parentCount := rand.Intn(2) + 1
|
||||||
|
|
||||||
|
for j := 0; j < parentCount; j++ {
|
||||||
|
reuseParent := rand.Intn(6) != 1 && j <= len(pool)-1 && j != 0
|
||||||
|
var newParent *models.Commit
|
||||||
|
if reuseParent {
|
||||||
|
newParent = pool[j]
|
||||||
|
} else {
|
||||||
|
newParent = &models.Commit{
|
||||||
|
Sha: fmt.Sprintf("%s%d", currentCommit.Sha, j),
|
||||||
|
Author: authorPool[rand.Intn(len(authorPool))],
|
||||||
|
}
|
||||||
|
pool = append(pool, newParent)
|
||||||
|
}
|
||||||
|
currentCommit.Parents = append(currentCommit.Parents, newParent.Sha)
|
||||||
|
}
|
||||||
|
|
||||||
|
commits = append(commits, currentCommit)
|
||||||
|
}
|
||||||
|
|
||||||
|
return commits
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
package gui
|
package gui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -50,14 +51,19 @@ func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error
|
|||||||
|
|
||||||
manager := gui.getManager(view)
|
manager := gui.getManager(view)
|
||||||
|
|
||||||
ptmx, err := pty.Start(cmd)
|
start := func() (*exec.Cmd, io.Reader) {
|
||||||
if err != nil {
|
ptmx, err := pty.Start(cmd)
|
||||||
return err
|
if err != nil {
|
||||||
|
gui.Log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gui.State.Ptmx = ptmx
|
||||||
|
|
||||||
|
return cmd, ptmx
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.State.Ptmx = ptmx
|
|
||||||
onClose := func() {
|
onClose := func() {
|
||||||
ptmx.Close()
|
gui.State.Ptmx.Close()
|
||||||
gui.State.Ptmx = nil
|
gui.State.Ptmx = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +71,7 @@ func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := manager.NewTask(manager.NewCmdTask(ptmx, cmd, prefix, height+oy+10, onClose), cmdStr); err != nil {
|
if err := manager.NewTask(manager.NewCmdTask(start, prefix, height+oy+10, onClose), cmdStr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,19 +39,19 @@ func TestMerge(t *testing.T) {
|
|||||||
{
|
{
|
||||||
"no color",
|
"no color",
|
||||||
nil,
|
nil,
|
||||||
TextStyle{style: color.Style{}},
|
TextStyle{Style: color.Style{}},
|
||||||
"foo",
|
"foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"only fg color",
|
"only fg color",
|
||||||
[]TextStyle{FgRed},
|
[]TextStyle{FgRed},
|
||||||
TextStyle{fg: &Color{basic: &fgRed}, style: color.Style{fgRed}},
|
TextStyle{fg: &Color{basic: &fgRed}, Style: color.Style{fgRed}},
|
||||||
"\x1b[31mfoo\x1b[0m",
|
"\x1b[31mfoo\x1b[0m",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"only bg color",
|
"only bg color",
|
||||||
[]TextStyle{BgRed},
|
[]TextStyle{BgRed},
|
||||||
TextStyle{bg: &Color{basic: &bgRed}, style: color.Style{bgRed}},
|
TextStyle{bg: &Color{basic: &bgRed}, Style: color.Style{bgRed}},
|
||||||
"\x1b[41mfoo\x1b[0m",
|
"\x1b[41mfoo\x1b[0m",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -60,7 +60,7 @@ func TestMerge(t *testing.T) {
|
|||||||
TextStyle{
|
TextStyle{
|
||||||
fg: &Color{basic: &fgBlue},
|
fg: &Color{basic: &fgBlue},
|
||||||
bg: &Color{basic: &bgRed},
|
bg: &Color{basic: &bgRed},
|
||||||
style: color.Style{fgBlue, bgRed},
|
Style: color.Style{fgBlue, bgRed},
|
||||||
},
|
},
|
||||||
"\x1b[34;41mfoo\x1b[0m",
|
"\x1b[34;41mfoo\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -69,7 +69,7 @@ func TestMerge(t *testing.T) {
|
|||||||
[]TextStyle{AttrBold},
|
[]TextStyle{AttrBold},
|
||||||
TextStyle{
|
TextStyle{
|
||||||
decoration: Decoration{bold: true},
|
decoration: Decoration{bold: true},
|
||||||
style: color.Style{color.OpBold},
|
Style: color.Style{color.OpBold},
|
||||||
},
|
},
|
||||||
"\x1b[1mfoo\x1b[0m",
|
"\x1b[1mfoo\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -81,7 +81,7 @@ func TestMerge(t *testing.T) {
|
|||||||
bold: true,
|
bold: true,
|
||||||
underline: true,
|
underline: true,
|
||||||
},
|
},
|
||||||
style: color.Style{color.OpBold, color.OpUnderscore},
|
Style: color.Style{color.OpBold, color.OpUnderscore},
|
||||||
},
|
},
|
||||||
"\x1b[1;4mfoo\x1b[0m",
|
"\x1b[1;4mfoo\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -95,7 +95,7 @@ func TestMerge(t *testing.T) {
|
|||||||
bold: true,
|
bold: true,
|
||||||
underline: true,
|
underline: true,
|
||||||
},
|
},
|
||||||
style: color.Style{fgBlue, bgRed, color.OpBold, color.OpUnderscore},
|
Style: color.Style{fgBlue, bgRed, color.OpBold, color.OpUnderscore},
|
||||||
},
|
},
|
||||||
"\x1b[34;41;1;4mfoo\x1b[0m",
|
"\x1b[34;41;1;4mfoo\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -104,7 +104,7 @@ func TestMerge(t *testing.T) {
|
|||||||
[]TextStyle{New().SetFg(rgbPink)},
|
[]TextStyle{New().SetFg(rgbPink)},
|
||||||
TextStyle{
|
TextStyle{
|
||||||
fg: &rgbPink,
|
fg: &rgbPink,
|
||||||
style: color.NewRGBStyle(rgbPinkLib).SetOpts(color.Opts{}),
|
Style: color.NewRGBStyle(rgbPinkLib).SetOpts(color.Opts{}),
|
||||||
},
|
},
|
||||||
// '38;2' qualifies an RGB foreground color
|
// '38;2' qualifies an RGB foreground color
|
||||||
"\x1b[38;2;255;0;255mfoo\x1b[0m",
|
"\x1b[38;2;255;0;255mfoo\x1b[0m",
|
||||||
@ -115,7 +115,7 @@ func TestMerge(t *testing.T) {
|
|||||||
TextStyle{
|
TextStyle{
|
||||||
fg: &rgbPink,
|
fg: &rgbPink,
|
||||||
bg: &rgbYellow,
|
bg: &rgbYellow,
|
||||||
style: color.NewRGBStyle(rgbPinkLib, rgbYellowLib).SetOpts(color.Opts{}),
|
Style: color.NewRGBStyle(rgbPinkLib, rgbYellowLib).SetOpts(color.Opts{}),
|
||||||
},
|
},
|
||||||
// '48;2' qualifies an RGB background color
|
// '48;2' qualifies an RGB background color
|
||||||
"\x1b[38;2;255;0;255;48;2;255;255;0mfoo\x1b[0m",
|
"\x1b[38;2;255;0;255;48;2;255;255;0mfoo\x1b[0m",
|
||||||
@ -130,7 +130,7 @@ func TestMerge(t *testing.T) {
|
|||||||
bold: true,
|
bold: true,
|
||||||
underline: true,
|
underline: true,
|
||||||
},
|
},
|
||||||
style: color.NewRGBStyle(rgbPinkLib, rgbYellowLib).SetOpts(color.Opts{color.OpBold, color.OpUnderscore}),
|
Style: color.NewRGBStyle(rgbPinkLib, rgbYellowLib).SetOpts(color.Opts{color.OpBold, color.OpUnderscore}),
|
||||||
},
|
},
|
||||||
"\x1b[38;2;255;0;255;48;2;255;255;0;1;4mfoo\x1b[0m",
|
"\x1b[38;2;255;0;255;48;2;255;255;0;1;4mfoo\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -140,7 +140,7 @@ func TestMerge(t *testing.T) {
|
|||||||
TextStyle{
|
TextStyle{
|
||||||
fg: &rgbYellow,
|
fg: &rgbYellow,
|
||||||
bg: &Color{basic: &bgRed},
|
bg: &Color{basic: &bgRed},
|
||||||
style: color.NewRGBStyle(
|
Style: color.NewRGBStyle(
|
||||||
rgbYellowLib,
|
rgbYellowLib,
|
||||||
fgRed.RGB(), // We need to use FG here, https://github.com/gookit/color/issues/39
|
fgRed.RGB(), // We need to use FG here, https://github.com/gookit/color/issues/39
|
||||||
).SetOpts(color.Opts{}),
|
).SetOpts(color.Opts{}),
|
||||||
|
@ -30,7 +30,9 @@ type TextStyle struct {
|
|||||||
bg *Color
|
bg *Color
|
||||||
decoration Decoration
|
decoration Decoration
|
||||||
|
|
||||||
style Sprinter
|
// making this public so that we can use a type switch to get to the underlying
|
||||||
|
// value so we can cache styles. This is very much a hack.
|
||||||
|
Style Sprinter
|
||||||
}
|
}
|
||||||
|
|
||||||
type Sprinter interface {
|
type Sprinter interface {
|
||||||
@ -40,16 +42,16 @@ type Sprinter interface {
|
|||||||
|
|
||||||
func New() TextStyle {
|
func New() TextStyle {
|
||||||
s := TextStyle{}
|
s := TextStyle{}
|
||||||
s.style = s.deriveStyle()
|
s.Style = s.deriveStyle()
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b TextStyle) Sprint(a ...interface{}) string {
|
func (b TextStyle) Sprint(a ...interface{}) string {
|
||||||
return b.style.Sprint(a...)
|
return b.Style.Sprint(a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b TextStyle) Sprintf(format string, a ...interface{}) string {
|
func (b TextStyle) Sprintf(format string, a ...interface{}) string {
|
||||||
return b.style.Sprintf(format, a...)
|
return b.Style.Sprintf(format, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that our receiver here is not a pointer which means we're receiving a
|
// note that our receiver here is not a pointer which means we're receiving a
|
||||||
@ -57,31 +59,31 @@ func (b TextStyle) Sprintf(format string, a ...interface{}) string {
|
|||||||
// TextStyle receiver without actually modifying the original.
|
// TextStyle receiver without actually modifying the original.
|
||||||
func (b TextStyle) SetBold() TextStyle {
|
func (b TextStyle) SetBold() TextStyle {
|
||||||
b.decoration.SetBold()
|
b.decoration.SetBold()
|
||||||
b.style = b.deriveStyle()
|
b.Style = b.deriveStyle()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b TextStyle) SetUnderline() TextStyle {
|
func (b TextStyle) SetUnderline() TextStyle {
|
||||||
b.decoration.SetUnderline()
|
b.decoration.SetUnderline()
|
||||||
b.style = b.deriveStyle()
|
b.Style = b.deriveStyle()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b TextStyle) SetReverse() TextStyle {
|
func (b TextStyle) SetReverse() TextStyle {
|
||||||
b.decoration.SetReverse()
|
b.decoration.SetReverse()
|
||||||
b.style = b.deriveStyle()
|
b.Style = b.deriveStyle()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b TextStyle) SetBg(color Color) TextStyle {
|
func (b TextStyle) SetBg(color Color) TextStyle {
|
||||||
b.bg = &color
|
b.bg = &color
|
||||||
b.style = b.deriveStyle()
|
b.Style = b.deriveStyle()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b TextStyle) SetFg(color Color) TextStyle {
|
func (b TextStyle) SetFg(color Color) TextStyle {
|
||||||
b.fg = &color
|
b.fg = &color
|
||||||
b.style = b.deriveStyle()
|
b.Style = b.deriveStyle()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +98,7 @@ func (b TextStyle) MergeStyle(other TextStyle) TextStyle {
|
|||||||
b.bg = other.bg
|
b.bg = other.bg
|
||||||
}
|
}
|
||||||
|
|
||||||
b.style = b.deriveStyle()
|
b.Style = b.deriveStyle()
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package gui
|
package gui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -20,18 +21,22 @@ func (gui *Gui) newCmdTask(view *gocui.View, cmd *exec.Cmd, prefix string) error
|
|||||||
|
|
||||||
manager := gui.getManager(view)
|
manager := gui.getManager(view)
|
||||||
|
|
||||||
r, err := cmd.StdoutPipe()
|
start := func() (*exec.Cmd, io.Reader) {
|
||||||
if err != nil {
|
r, err := cmd.StdoutPipe()
|
||||||
return err
|
if err != nil {
|
||||||
}
|
gui.Log.Warn(err)
|
||||||
cmd.Stderr = cmd.Stdout
|
}
|
||||||
|
cmd.Stderr = cmd.Stdout
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return err
|
gui.Log.Warn(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd, r
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := manager.NewTask(manager.NewCmdTask(r, cmd, prefix, height+oy+10, nil), cmdStr); err != nil {
|
if err := manager.NewTask(manager.NewCmdTask(start, prefix, height+oy+10, nil), cmdStr); err != nil {
|
||||||
return err
|
gui.Log.Warn(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -90,7 +95,6 @@ func (gui *Gui) getManager(view *gocui.View) *tasks.ViewBufferManager {
|
|||||||
view.Reset()
|
view.Reset()
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
// gui.g.Draw(view) // doing this causes an issue when there's a popup panel in front of the main view.
|
|
||||||
gui.render()
|
gui.render()
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
|
@ -308,6 +308,11 @@ func (gui *Gui) renderDisplayStrings(v *gocui.View, displayStrings [][]string) {
|
|||||||
v.SetContent(list)
|
v.SetContent(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) renderDisplayStringsAtPos(v *gocui.View, y int, displayStrings [][]string) {
|
||||||
|
list := utils.RenderDisplayStrings(displayStrings)
|
||||||
|
v.OverwriteLines(y, list)
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) globalOptionsMap() map[string]string {
|
func (gui *Gui) globalOptionsMap() map[string]string {
|
||||||
keybindingConfig := gui.Config.GetUserConfig().Keybinding
|
keybindingConfig := gui.Config.GetUserConfig().Keybinding
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const THROTTLE_TIME = time.Millisecond * 30
|
||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
stopped bool
|
stopped bool
|
||||||
@ -38,6 +40,12 @@ type ViewBufferManager struct {
|
|||||||
beforeStart func()
|
beforeStart func()
|
||||||
refreshView func()
|
refreshView func()
|
||||||
onEndOfInput func()
|
onEndOfInput func()
|
||||||
|
|
||||||
|
// if the user flicks through a heap of items, with each one
|
||||||
|
// spawning a process to render something to the main view,
|
||||||
|
// it can slow things down quite a bit. In these situations we
|
||||||
|
// want to throttle the spawning of processes.
|
||||||
|
throttle bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ViewBufferManager) GetTaskKey() string {
|
func (m *ViewBufferManager) GetTaskKey() string {
|
||||||
@ -69,18 +77,31 @@ func (m *ViewBufferManager) ReadLines(n int) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string, linesToRead int, onDone func()) func(chan struct{}) error {
|
func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), prefix string, linesToRead int, onDone func()) func(chan struct{}) error {
|
||||||
return func(stop chan struct{}) error {
|
return func(stop chan struct{}) error {
|
||||||
|
if m.throttle {
|
||||||
|
m.Log.Info("throttling task")
|
||||||
|
time.Sleep(THROTTLE_TIME)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-stop:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
startTime := time.Now()
|
||||||
|
|
||||||
|
cmd, r := start()
|
||||||
|
|
||||||
go utils.Safe(func() {
|
go utils.Safe(func() {
|
||||||
<-stop
|
<-stop
|
||||||
|
m.throttle = time.Since(startTime) < THROTTLE_TIME
|
||||||
if err := oscommands.Kill(cmd); err != nil {
|
if err := oscommands.Kill(cmd); err != nil {
|
||||||
if !strings.Contains(err.Error(), "process already finished") {
|
if !strings.Contains(err.Error(), "process already finished") {
|
||||||
m.Log.Errorf("error when running cmd task: %v", err)
|
m.Log.Errorf("error when running cmd task: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if onDone != nil {
|
|
||||||
onDone()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
loadingMutex := sync.Mutex{}
|
loadingMutex := sync.Mutex{}
|
||||||
|
@ -6,21 +6,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var decoloriseCache = make(map[string]string)
|
var decoloriseCache = make(map[string]string)
|
||||||
var decoloriseMutex sync.Mutex
|
var decoloriseMutex sync.RWMutex
|
||||||
|
|
||||||
// Decolorise strips a string of color
|
// Decolorise strips a string of color
|
||||||
func Decolorise(str string) string {
|
func Decolorise(str string) string {
|
||||||
decoloriseMutex.Lock()
|
decoloriseMutex.RLock()
|
||||||
defer decoloriseMutex.Unlock()
|
val := decoloriseCache[str]
|
||||||
|
decoloriseMutex.RUnlock()
|
||||||
|
|
||||||
if decoloriseCache[str] != "" {
|
if val != "" {
|
||||||
return decoloriseCache[str]
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
re := regexp.MustCompile(`\x1B\[([0-9]{1,3}(;[0-9]{1,3})*)?[mGK]`)
|
re := regexp.MustCompile(`\x1B\[([0-9]{1,3}(;[0-9]{1,3})*)?[mGK]`)
|
||||||
ret := re.ReplaceAllString(str, "")
|
ret := re.ReplaceAllString(str, "")
|
||||||
|
|
||||||
|
decoloriseMutex.Lock()
|
||||||
decoloriseCache[str] = ret
|
decoloriseCache[str] = ret
|
||||||
|
decoloriseMutex.Unlock()
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
16
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
16
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
@ -75,8 +75,6 @@ type GuiMutexes struct {
|
|||||||
tickingMutex sync.Mutex
|
tickingMutex sync.Mutex
|
||||||
|
|
||||||
ViewsMutex sync.Mutex
|
ViewsMutex sync.Mutex
|
||||||
|
|
||||||
drawMutex sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlayMode int
|
type PlayMode int
|
||||||
@ -936,8 +934,6 @@ func (g *Gui) drawListFooter(v *View, fgColor, bgColor Attribute) error {
|
|||||||
|
|
||||||
// flush updates the gui, re-drawing frames and buffers.
|
// flush updates the gui, re-drawing frames and buffers.
|
||||||
func (g *Gui) flush() error {
|
func (g *Gui) flush() error {
|
||||||
g.Mutexes.drawMutex.Lock()
|
|
||||||
defer g.Mutexes.drawMutex.Unlock()
|
|
||||||
|
|
||||||
// pretty sure we don't need this, but keeping it here in case we get weird visual artifacts
|
// pretty sure we don't need this, but keeping it here in case we get weird visual artifacts
|
||||||
// g.clear(g.FgColor, g.BgColor)
|
// g.clear(g.FgColor, g.BgColor)
|
||||||
@ -966,18 +962,6 @@ func (g *Gui) flush() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gui) Draw(v *View) error {
|
|
||||||
g.Mutexes.drawMutex.Lock()
|
|
||||||
defer g.Mutexes.drawMutex.Unlock()
|
|
||||||
|
|
||||||
if err := g.draw(v); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
Screen.Show()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw manages the cursor and calls the draw function of a view.
|
// draw manages the cursor and calls the draw function of a view.
|
||||||
func (g *Gui) draw(v *View) error {
|
func (g *Gui) draw(v *View) error {
|
||||||
if g.suspended {
|
if g.suspended {
|
||||||
|
36
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
36
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -879,11 +879,18 @@ func (v *View) draw() error {
|
|||||||
if v.Autoscroll && visibleViewLinesHeight > maxY {
|
if v.Autoscroll && visibleViewLinesHeight > maxY {
|
||||||
v.oy = visibleViewLinesHeight - maxY
|
v.oy = visibleViewLinesHeight - maxY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(v.viewLines) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
start := v.oy
|
||||||
|
if start > len(v.viewLines)-1 {
|
||||||
|
start = len(v.viewLines) - 1
|
||||||
|
}
|
||||||
|
|
||||||
y := 0
|
y := 0
|
||||||
for i, vline := range v.viewLines {
|
for _, vline := range v.viewLines[start:] {
|
||||||
if i < v.oy {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if y >= maxY {
|
if y >= maxY {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1112,14 +1119,6 @@ func (v *View) SetHighlight(y int, on bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func lineWidth(line []cell) (n int) {
|
|
||||||
for i := range line {
|
|
||||||
n += runewidth.RuneWidth(line[i].chr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func lineWrap(line []cell, columns int) [][]cell {
|
func lineWrap(line []cell, columns int) [][]cell {
|
||||||
if columns == 0 {
|
if columns == 0 {
|
||||||
return [][]cell{line}
|
return [][]cell{line}
|
||||||
@ -1227,3 +1226,16 @@ func (v *View) ClearTextArea() {
|
|||||||
_ = v.SetOrigin(0, 0)
|
_ = v.SetOrigin(0, 0)
|
||||||
_ = v.SetCursor(0, 0)
|
_ = v.SetCursor(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only call this function if you don't care where v.wx and v.wy end up
|
||||||
|
func (v *View) OverwriteLines(y int, content string) {
|
||||||
|
v.writeMutex.Lock()
|
||||||
|
defer v.writeMutex.Unlock()
|
||||||
|
|
||||||
|
// break by newline, then for each line, write it, then add that erase command
|
||||||
|
v.wx = 0
|
||||||
|
v.wy = y
|
||||||
|
|
||||||
|
lines := strings.Replace(content, "\n", "\x1b[K\n", -1)
|
||||||
|
v.writeString(lines)
|
||||||
|
}
|
||||||
|
21
vendor/golang.org/x/sys/unix/syscall_darwin.go
generated
vendored
21
vendor/golang.org/x/sys/unix/syscall_darwin.go
generated
vendored
@ -430,8 +430,25 @@ func GetsockoptXucred(fd, level, opt int) (*Xucred, error) {
|
|||||||
return x, err
|
return x, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) {
|
func SysctlKinfoProc(name string, args ...int) (*KinfoProc, error) {
|
||||||
mib, err := sysctlmib(name)
|
mib, err := sysctlmib(name, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var kinfo KinfoProc
|
||||||
|
n := uintptr(SizeofKinfoProc)
|
||||||
|
if err := sysctl(mib, (*byte)(unsafe.Pointer(&kinfo)), &n, nil, 0); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n != SizeofKinfoProc {
|
||||||
|
return nil, EIO
|
||||||
|
}
|
||||||
|
return &kinfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) {
|
||||||
|
mib, err := sysctlmib(name, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
26
vendor/golang.org/x/sys/unix/zerrors_linux.go
generated
vendored
26
vendor/golang.org/x/sys/unix/zerrors_linux.go
generated
vendored
@ -116,6 +116,7 @@ const (
|
|||||||
ARPHRD_LAPB = 0x204
|
ARPHRD_LAPB = 0x204
|
||||||
ARPHRD_LOCALTLK = 0x305
|
ARPHRD_LOCALTLK = 0x305
|
||||||
ARPHRD_LOOPBACK = 0x304
|
ARPHRD_LOOPBACK = 0x304
|
||||||
|
ARPHRD_MCTP = 0x122
|
||||||
ARPHRD_METRICOM = 0x17
|
ARPHRD_METRICOM = 0x17
|
||||||
ARPHRD_NETLINK = 0x338
|
ARPHRD_NETLINK = 0x338
|
||||||
ARPHRD_NETROM = 0x0
|
ARPHRD_NETROM = 0x0
|
||||||
@ -472,6 +473,7 @@ const (
|
|||||||
DM_DEV_WAIT = 0xc138fd08
|
DM_DEV_WAIT = 0xc138fd08
|
||||||
DM_DIR = "mapper"
|
DM_DIR = "mapper"
|
||||||
DM_GET_TARGET_VERSION = 0xc138fd11
|
DM_GET_TARGET_VERSION = 0xc138fd11
|
||||||
|
DM_IMA_MEASUREMENT_FLAG = 0x80000
|
||||||
DM_INACTIVE_PRESENT_FLAG = 0x40
|
DM_INACTIVE_PRESENT_FLAG = 0x40
|
||||||
DM_INTERNAL_SUSPEND_FLAG = 0x40000
|
DM_INTERNAL_SUSPEND_FLAG = 0x40000
|
||||||
DM_IOCTL = 0xfd
|
DM_IOCTL = 0xfd
|
||||||
@ -716,6 +718,7 @@ const (
|
|||||||
ETH_P_LOOPBACK = 0x9000
|
ETH_P_LOOPBACK = 0x9000
|
||||||
ETH_P_MACSEC = 0x88e5
|
ETH_P_MACSEC = 0x88e5
|
||||||
ETH_P_MAP = 0xf9
|
ETH_P_MAP = 0xf9
|
||||||
|
ETH_P_MCTP = 0xfa
|
||||||
ETH_P_MOBITEX = 0x15
|
ETH_P_MOBITEX = 0x15
|
||||||
ETH_P_MPLS_MC = 0x8848
|
ETH_P_MPLS_MC = 0x8848
|
||||||
ETH_P_MPLS_UC = 0x8847
|
ETH_P_MPLS_UC = 0x8847
|
||||||
@ -751,6 +754,21 @@ const (
|
|||||||
ETH_P_WCCP = 0x883e
|
ETH_P_WCCP = 0x883e
|
||||||
ETH_P_X25 = 0x805
|
ETH_P_X25 = 0x805
|
||||||
ETH_P_XDSA = 0xf8
|
ETH_P_XDSA = 0xf8
|
||||||
|
EV_ABS = 0x3
|
||||||
|
EV_CNT = 0x20
|
||||||
|
EV_FF = 0x15
|
||||||
|
EV_FF_STATUS = 0x17
|
||||||
|
EV_KEY = 0x1
|
||||||
|
EV_LED = 0x11
|
||||||
|
EV_MAX = 0x1f
|
||||||
|
EV_MSC = 0x4
|
||||||
|
EV_PWR = 0x16
|
||||||
|
EV_REL = 0x2
|
||||||
|
EV_REP = 0x14
|
||||||
|
EV_SND = 0x12
|
||||||
|
EV_SW = 0x5
|
||||||
|
EV_SYN = 0x0
|
||||||
|
EV_VERSION = 0x10001
|
||||||
EXABYTE_ENABLE_NEST = 0xf0
|
EXABYTE_ENABLE_NEST = 0xf0
|
||||||
EXT2_SUPER_MAGIC = 0xef53
|
EXT2_SUPER_MAGIC = 0xef53
|
||||||
EXT3_SUPER_MAGIC = 0xef53
|
EXT3_SUPER_MAGIC = 0xef53
|
||||||
@ -789,9 +807,11 @@ const (
|
|||||||
FAN_DELETE_SELF = 0x400
|
FAN_DELETE_SELF = 0x400
|
||||||
FAN_DENY = 0x2
|
FAN_DENY = 0x2
|
||||||
FAN_ENABLE_AUDIT = 0x40
|
FAN_ENABLE_AUDIT = 0x40
|
||||||
|
FAN_EPIDFD = -0x2
|
||||||
FAN_EVENT_INFO_TYPE_DFID = 0x3
|
FAN_EVENT_INFO_TYPE_DFID = 0x3
|
||||||
FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2
|
FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2
|
||||||
FAN_EVENT_INFO_TYPE_FID = 0x1
|
FAN_EVENT_INFO_TYPE_FID = 0x1
|
||||||
|
FAN_EVENT_INFO_TYPE_PIDFD = 0x4
|
||||||
FAN_EVENT_METADATA_LEN = 0x18
|
FAN_EVENT_METADATA_LEN = 0x18
|
||||||
FAN_EVENT_ON_CHILD = 0x8000000
|
FAN_EVENT_ON_CHILD = 0x8000000
|
||||||
FAN_MARK_ADD = 0x1
|
FAN_MARK_ADD = 0x1
|
||||||
@ -811,6 +831,7 @@ const (
|
|||||||
FAN_MOVE_SELF = 0x800
|
FAN_MOVE_SELF = 0x800
|
||||||
FAN_NOFD = -0x1
|
FAN_NOFD = -0x1
|
||||||
FAN_NONBLOCK = 0x2
|
FAN_NONBLOCK = 0x2
|
||||||
|
FAN_NOPIDFD = -0x1
|
||||||
FAN_ONDIR = 0x40000000
|
FAN_ONDIR = 0x40000000
|
||||||
FAN_OPEN = 0x20
|
FAN_OPEN = 0x20
|
||||||
FAN_OPEN_EXEC = 0x1000
|
FAN_OPEN_EXEC = 0x1000
|
||||||
@ -821,6 +842,7 @@ const (
|
|||||||
FAN_REPORT_DIR_FID = 0x400
|
FAN_REPORT_DIR_FID = 0x400
|
||||||
FAN_REPORT_FID = 0x200
|
FAN_REPORT_FID = 0x200
|
||||||
FAN_REPORT_NAME = 0x800
|
FAN_REPORT_NAME = 0x800
|
||||||
|
FAN_REPORT_PIDFD = 0x80
|
||||||
FAN_REPORT_TID = 0x100
|
FAN_REPORT_TID = 0x100
|
||||||
FAN_UNLIMITED_MARKS = 0x20
|
FAN_UNLIMITED_MARKS = 0x20
|
||||||
FAN_UNLIMITED_QUEUE = 0x10
|
FAN_UNLIMITED_QUEUE = 0x10
|
||||||
@ -1997,6 +2019,7 @@ const (
|
|||||||
PR_SPEC_ENABLE = 0x2
|
PR_SPEC_ENABLE = 0x2
|
||||||
PR_SPEC_FORCE_DISABLE = 0x8
|
PR_SPEC_FORCE_DISABLE = 0x8
|
||||||
PR_SPEC_INDIRECT_BRANCH = 0x1
|
PR_SPEC_INDIRECT_BRANCH = 0x1
|
||||||
|
PR_SPEC_L1D_FLUSH = 0x2
|
||||||
PR_SPEC_NOT_AFFECTED = 0x0
|
PR_SPEC_NOT_AFFECTED = 0x0
|
||||||
PR_SPEC_PRCTL = 0x1
|
PR_SPEC_PRCTL = 0x1
|
||||||
PR_SPEC_STORE_BYPASS = 0x0
|
PR_SPEC_STORE_BYPASS = 0x0
|
||||||
@ -2432,12 +2455,15 @@ const (
|
|||||||
SMART_WRITE_THRESHOLDS = 0xd7
|
SMART_WRITE_THRESHOLDS = 0xd7
|
||||||
SMB_SUPER_MAGIC = 0x517b
|
SMB_SUPER_MAGIC = 0x517b
|
||||||
SOCKFS_MAGIC = 0x534f434b
|
SOCKFS_MAGIC = 0x534f434b
|
||||||
|
SOCK_BUF_LOCK_MASK = 0x3
|
||||||
SOCK_DCCP = 0x6
|
SOCK_DCCP = 0x6
|
||||||
SOCK_IOC_TYPE = 0x89
|
SOCK_IOC_TYPE = 0x89
|
||||||
SOCK_PACKET = 0xa
|
SOCK_PACKET = 0xa
|
||||||
SOCK_RAW = 0x3
|
SOCK_RAW = 0x3
|
||||||
|
SOCK_RCVBUF_LOCK = 0x2
|
||||||
SOCK_RDM = 0x4
|
SOCK_RDM = 0x4
|
||||||
SOCK_SEQPACKET = 0x5
|
SOCK_SEQPACKET = 0x5
|
||||||
|
SOCK_SNDBUF_LOCK = 0x1
|
||||||
SOL_AAL = 0x109
|
SOL_AAL = 0x109
|
||||||
SOL_ALG = 0x117
|
SOL_ALG = 0x117
|
||||||
SOL_ATM = 0x108
|
SOL_ATM = 0x108
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_386.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_386.go
generated
vendored
@ -293,6 +293,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
generated
vendored
@ -294,6 +294,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
generated
vendored
@ -300,6 +300,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
generated
vendored
@ -290,6 +290,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
generated
vendored
@ -293,6 +293,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x20
|
SO_BROADCAST = 0x20
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
generated
vendored
@ -293,6 +293,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x20
|
SO_BROADCAST = 0x20
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
generated
vendored
@ -293,6 +293,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x20
|
SO_BROADCAST = 0x20
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
generated
vendored
@ -293,6 +293,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x20
|
SO_BROADCAST = 0x20
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
generated
vendored
@ -348,6 +348,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
generated
vendored
@ -352,6 +352,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
generated
vendored
@ -352,6 +352,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
generated
vendored
@ -281,6 +281,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
generated
vendored
@ -356,6 +356,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x30
|
SO_BPF_EXTENSIONS = 0x30
|
||||||
SO_BROADCAST = 0x6
|
SO_BROADCAST = 0x6
|
||||||
SO_BSDCOMPAT = 0xe
|
SO_BSDCOMPAT = 0xe
|
||||||
|
SO_BUF_LOCK = 0x48
|
||||||
SO_BUSY_POLL = 0x2e
|
SO_BUSY_POLL = 0x2e
|
||||||
SO_BUSY_POLL_BUDGET = 0x46
|
SO_BUSY_POLL_BUDGET = 0x46
|
||||||
SO_CNX_ADVICE = 0x35
|
SO_CNX_ADVICE = 0x35
|
||||||
|
1
vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
generated
vendored
@ -347,6 +347,7 @@ const (
|
|||||||
SO_BPF_EXTENSIONS = 0x32
|
SO_BPF_EXTENSIONS = 0x32
|
||||||
SO_BROADCAST = 0x20
|
SO_BROADCAST = 0x20
|
||||||
SO_BSDCOMPAT = 0x400
|
SO_BSDCOMPAT = 0x400
|
||||||
|
SO_BUF_LOCK = 0x51
|
||||||
SO_BUSY_POLL = 0x30
|
SO_BUSY_POLL = 0x30
|
||||||
SO_BUSY_POLL_BUDGET = 0x49
|
SO_BUSY_POLL_BUDGET = 0x49
|
||||||
SO_CNX_ADVICE = 0x37
|
SO_CNX_ADVICE = 0x37
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
generated
vendored
@ -444,4 +444,5 @@ const (
|
|||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
SYS_MEMFD_SECRET = 447
|
SYS_MEMFD_SECRET = 447
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
generated
vendored
@ -366,4 +366,5 @@ const (
|
|||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
SYS_MEMFD_SECRET = 447
|
SYS_MEMFD_SECRET = 447
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
2
vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
generated
vendored
@ -7,6 +7,7 @@
|
|||||||
package unix
|
package unix
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
SYS_SYSCALL_MASK = 0
|
||||||
SYS_RESTART_SYSCALL = 0
|
SYS_RESTART_SYSCALL = 0
|
||||||
SYS_EXIT = 1
|
SYS_EXIT = 1
|
||||||
SYS_FORK = 2
|
SYS_FORK = 2
|
||||||
@ -407,4 +408,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
generated
vendored
@ -311,4 +311,5 @@ const (
|
|||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
SYS_MEMFD_SECRET = 447
|
SYS_MEMFD_SECRET = 447
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
generated
vendored
@ -428,4 +428,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 4444
|
SYS_LANDLOCK_CREATE_RULESET = 4444
|
||||||
SYS_LANDLOCK_ADD_RULE = 4445
|
SYS_LANDLOCK_ADD_RULE = 4445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 4446
|
SYS_LANDLOCK_RESTRICT_SELF = 4446
|
||||||
|
SYS_PROCESS_MRELEASE = 4448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
generated
vendored
@ -358,4 +358,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 5444
|
SYS_LANDLOCK_CREATE_RULESET = 5444
|
||||||
SYS_LANDLOCK_ADD_RULE = 5445
|
SYS_LANDLOCK_ADD_RULE = 5445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 5446
|
SYS_LANDLOCK_RESTRICT_SELF = 5446
|
||||||
|
SYS_PROCESS_MRELEASE = 5448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
generated
vendored
@ -358,4 +358,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 5444
|
SYS_LANDLOCK_CREATE_RULESET = 5444
|
||||||
SYS_LANDLOCK_ADD_RULE = 5445
|
SYS_LANDLOCK_ADD_RULE = 5445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 5446
|
SYS_LANDLOCK_RESTRICT_SELF = 5446
|
||||||
|
SYS_PROCESS_MRELEASE = 5448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
generated
vendored
@ -428,4 +428,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 4444
|
SYS_LANDLOCK_CREATE_RULESET = 4444
|
||||||
SYS_LANDLOCK_ADD_RULE = 4445
|
SYS_LANDLOCK_ADD_RULE = 4445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 4446
|
SYS_LANDLOCK_RESTRICT_SELF = 4446
|
||||||
|
SYS_PROCESS_MRELEASE = 4448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
generated
vendored
@ -435,4 +435,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
generated
vendored
@ -407,4 +407,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
generated
vendored
@ -407,4 +407,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
generated
vendored
@ -309,4 +309,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
generated
vendored
@ -372,4 +372,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
1
vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
generated
vendored
@ -386,4 +386,5 @@ const (
|
|||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
)
|
)
|
||||||
|
7
vendor/golang.org/x/sys/unix/ztypes_linux.go
generated
vendored
7
vendor/golang.org/x/sys/unix/ztypes_linux.go
generated
vendored
@ -3264,7 +3264,8 @@ const (
|
|||||||
LWTUNNEL_ENCAP_BPF = 0x6
|
LWTUNNEL_ENCAP_BPF = 0x6
|
||||||
LWTUNNEL_ENCAP_SEG6_LOCAL = 0x7
|
LWTUNNEL_ENCAP_SEG6_LOCAL = 0x7
|
||||||
LWTUNNEL_ENCAP_RPL = 0x8
|
LWTUNNEL_ENCAP_RPL = 0x8
|
||||||
LWTUNNEL_ENCAP_MAX = 0x8
|
LWTUNNEL_ENCAP_IOAM6 = 0x9
|
||||||
|
LWTUNNEL_ENCAP_MAX = 0x9
|
||||||
|
|
||||||
MPLS_IPTUNNEL_UNSPEC = 0x0
|
MPLS_IPTUNNEL_UNSPEC = 0x0
|
||||||
MPLS_IPTUNNEL_DST = 0x1
|
MPLS_IPTUNNEL_DST = 0x1
|
||||||
@ -3617,7 +3618,9 @@ const (
|
|||||||
ETHTOOL_A_COALESCE_TX_USECS_HIGH = 0x15
|
ETHTOOL_A_COALESCE_TX_USECS_HIGH = 0x15
|
||||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH = 0x16
|
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH = 0x16
|
||||||
ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 0x17
|
ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 0x17
|
||||||
ETHTOOL_A_COALESCE_MAX = 0x17
|
ETHTOOL_A_COALESCE_USE_CQE_MODE_TX = 0x18
|
||||||
|
ETHTOOL_A_COALESCE_USE_CQE_MODE_RX = 0x19
|
||||||
|
ETHTOOL_A_COALESCE_MAX = 0x19
|
||||||
ETHTOOL_A_PAUSE_UNSPEC = 0x0
|
ETHTOOL_A_PAUSE_UNSPEC = 0x0
|
||||||
ETHTOOL_A_PAUSE_HEADER = 0x1
|
ETHTOOL_A_PAUSE_HEADER = 0x1
|
||||||
ETHTOOL_A_PAUSE_AUTONEG = 0x2
|
ETHTOOL_A_PAUSE_AUTONEG = 0x2
|
||||||
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -161,7 +161,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
|
|||||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/index
|
github.com/jesseduffield/go-git/v5/utils/merkletrie/index
|
||||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
|
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
|
||||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
|
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
|
||||||
# github.com/jesseduffield/gocui v0.3.1-0.20211031223253-24baf341da75
|
# github.com/jesseduffield/gocui v0.3.1-0.20211102081536-e4eee64f4d13
|
||||||
## explicit
|
## explicit
|
||||||
github.com/jesseduffield/gocui
|
github.com/jesseduffield/gocui
|
||||||
# github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
# github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||||
@ -253,7 +253,7 @@ golang.org/x/crypto/ssh/knownhosts
|
|||||||
golang.org/x/net/context
|
golang.org/x/net/context
|
||||||
golang.org/x/net/internal/socks
|
golang.org/x/net/internal/socks
|
||||||
golang.org/x/net/proxy
|
golang.org/x/net/proxy
|
||||||
# golang.org/x/sys v0.0.0-20211031064116-611d5d643895
|
# golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/sys/cpu
|
golang.org/x/sys/cpu
|
||||||
golang.org/x/sys/internal/unsafeheader
|
golang.org/x/sys/internal/unsafeheader
|
||||||
|
Loading…
x
Reference in New Issue
Block a user