mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-12 00:26:24 -04:00
Merge branch 'master' into gh-integration
This commit is contained in:
commit
37aa558d34
|
|
@ -1,5 +1,5 @@
|
|||
# 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.
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,14 @@ git:
|
|||
manualCommit: false
|
||||
# extra args passed to `git merge`, e.g. --no-ff
|
||||
args: ''
|
||||
log:
|
||||
# one of date-order, author-date-order, topo-order.
|
||||
# topo-order makes it easier to read the git log graph, but commits may not
|
||||
# appear chronologically. See https://git-scm.com/docs/git-log#_commit_ordering
|
||||
order: 'topo-order'
|
||||
# one of always, never, when-maximised
|
||||
# this determines whether the git graph is rendered in the commits panel
|
||||
showGraph: 'when-maximised'
|
||||
skipHookPrefix: WIP
|
||||
autoFetch: true
|
||||
branchLogCmd: 'git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --'
|
||||
|
|
@ -100,11 +108,13 @@ keybinding:
|
|||
nextPage: '.' # go to previous page in list
|
||||
gotoTop: '<' # go to top of list
|
||||
gotoBottom: '>' # go to bottom of list
|
||||
scrollLeft: 'H' # scroll left within list view
|
||||
scrollRight: 'L' # scroll right within list view
|
||||
prevBlock: '<left>' # goto the previous block / panel
|
||||
nextBlock: '<right>' # goto the next block / panel
|
||||
prevBlock-alt: 'h' # goto the previous block / panel
|
||||
nextBlock-alt: 'l' # goto the next block / panel
|
||||
jumpToBlock: ["1", "2", "3", "4", "5"] # goto the Nth block / panel
|
||||
jumpToBlock: ['1', '2', '3', '4', '5'] # goto the Nth block / panel
|
||||
nextMatch: 'n'
|
||||
prevMatch: 'N'
|
||||
optionMenu: 'x' # show help menu
|
||||
|
|
@ -192,6 +202,7 @@ keybinding:
|
|||
checkoutCommit: '<space>'
|
||||
resetCherryPick: '<c-R>'
|
||||
copyCommitMessageToClipboard: '<c-y>'
|
||||
openLogMenu: '<c-l>'
|
||||
stash:
|
||||
popStash: 'g'
|
||||
commitFiles:
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -20,7 +20,7 @@ require (
|
|||
github.com/imdario/mergo v0.3.11
|
||||
github.com/integrii/flaggy v1.4.0
|
||||
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.20211102104458-40df0be5a474
|
||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||
github.com/jesseduffield/yaml v2.1.0+incompatible
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||
|
|
@ -40,7 +40,7 @@ require (
|
|||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // 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/text v0.3.7 // indirect
|
||||
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/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/gocui v0.3.1-0.20211031223253-24baf341da75 h1:zu+WBGwscCwu7GEuxANGl8E51HbW6ueqTF1XdAoqnZs=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20211031223253-24baf341da75/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20211102104458-40df0be5a474 h1:4H/oJcUmwJpqyXzqfn+lsjQ/bjpm/HszzLrVbCjgqj4=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20211102104458-40df0be5a474/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/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
|
||||
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-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-20211031064116-611d5d643895 h1:iaNpwpnrgL5jzWS0vCNnfa8HqzxveCFpFx3uC/X4Tps=
|
||||
golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c h1:QOfDMdrf/UwlVR0UBq2Mpr58UzNtvgJRXA4BgPfFACs=
|
||||
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-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
|
|
|||
|
|
@ -37,7 +37,12 @@ type CommitListBuilder struct {
|
|||
}
|
||||
|
||||
// NewCommitListBuilder builds a new commit list builder
|
||||
func NewCommitListBuilder(log *logrus.Entry, gitCommand *GitCommand, osCommand *oscommands.OSCommand, tr *i18n.TranslationSet) *CommitListBuilder {
|
||||
func NewCommitListBuilder(
|
||||
log *logrus.Entry,
|
||||
gitCommand *GitCommand,
|
||||
osCommand *oscommands.OSCommand,
|
||||
tr *i18n.TranslationSet,
|
||||
) *CommitListBuilder {
|
||||
return &CommitListBuilder{
|
||||
Log: log,
|
||||
GitCommand: gitCommand,
|
||||
|
|
@ -88,6 +93,8 @@ type GetCommitsOptions struct {
|
|||
FilterPath string
|
||||
IncludeRebaseCommits bool
|
||||
RefName string // e.g. "HEAD" or "my_branch"
|
||||
// determines if we show the whole git graph i.e. pass the '--all' flag
|
||||
All bool
|
||||
}
|
||||
|
||||
func (c *CommitListBuilder) MergeRebasingCommits(commits []*models.Commit) ([]*models.Commit, error) {
|
||||
|
|
@ -404,10 +411,20 @@ func (c *CommitListBuilder) getLogCmd(opts GetCommitsOptions) *exec.Cmd {
|
|||
filterFlag = fmt.Sprintf(" --follow -- %s", c.OSCommand.Quote(opts.FilterPath))
|
||||
}
|
||||
|
||||
config := c.GitCommand.Config.GetUserConfig().Git.Log
|
||||
|
||||
orderFlag := "--" + config.Order
|
||||
allFlag := ""
|
||||
if opts.All {
|
||||
allFlag = " --all"
|
||||
}
|
||||
|
||||
return c.OSCommand.ExecutableFromString(
|
||||
fmt.Sprintf(
|
||||
"git log %s --oneline %s %s --abbrev=%d %s",
|
||||
"git log %s %s %s --oneline %s %s --abbrev=%d %s",
|
||||
c.OSCommand.Quote(opts.RefName),
|
||||
orderFlag,
|
||||
allFlag,
|
||||
prettyFormat,
|
||||
limitFlag,
|
||||
20,
|
||||
|
|
|
|||
|
|
@ -69,8 +69,10 @@ type GitConfig struct {
|
|||
OverrideGpg bool `yaml:"overrideGpg"`
|
||||
DisableForcePushing bool `yaml:"disableForcePushing"`
|
||||
CommitPrefixes map[string]CommitPrefixConfig `yaml:"commitPrefixes"`
|
||||
ParseEmoji bool `yaml:"parseEmoji"`
|
||||
EnableGhCommand bool `yaml:"enableGhCommand"`
|
||||
// this shoudl really be under 'gui', not 'git'
|
||||
ParseEmoji bool `yaml:"parseEmoji"`
|
||||
Log LogConfig `yaml:"log"`
|
||||
EnableGhCommand bool `yaml:"enableGhCommand"`
|
||||
}
|
||||
|
||||
type PagingConfig struct {
|
||||
|
|
@ -84,6 +86,11 @@ type MergingConfig struct {
|
|||
Args string `yaml:"args"`
|
||||
}
|
||||
|
||||
type LogConfig struct {
|
||||
Order string `yaml:"order"` // one of date-order, author-date-order, topo-order
|
||||
ShowGraph string `yaml:"showGraph"` // one of always, never, when-maximised
|
||||
}
|
||||
|
||||
type CommitPrefixConfig struct {
|
||||
Pattern string `yaml:"pattern"`
|
||||
Replace string `yaml:"replace"`
|
||||
|
|
@ -119,6 +126,8 @@ type KeybindingUniversalConfig struct {
|
|||
NextItemAlt string `yaml:"nextItem-alt"`
|
||||
PrevPage string `yaml:"prevPage"`
|
||||
NextPage string `yaml:"nextPage"`
|
||||
ScrollLeft string `yaml:"scrollLeft"`
|
||||
ScrollRight string `yaml:"scrollRight"`
|
||||
GotoTop string `yaml:"gotoTop"`
|
||||
GotoBottom string `yaml:"gotoBottom"`
|
||||
PrevBlock string `yaml:"prevBlock"`
|
||||
|
|
@ -229,6 +238,7 @@ type KeybindingCommitsConfig struct {
|
|||
CheckoutCommit string `yaml:"checkoutCommit"`
|
||||
ResetCherryPick string `yaml:"resetCherryPick"`
|
||||
CopyCommitMessageToClipboard string `yaml:"copyCommitMessageToClipboard"`
|
||||
OpenLogMenu string `yaml:"openLogMenu"`
|
||||
}
|
||||
|
||||
type KeybindingStashConfig struct {
|
||||
|
|
@ -339,6 +349,10 @@ func GetDefaultConfig() *UserConfig {
|
|||
ManualCommit: false,
|
||||
Args: "",
|
||||
},
|
||||
Log: LogConfig{
|
||||
Order: "topo-order",
|
||||
ShowGraph: "when-maximised",
|
||||
},
|
||||
SkipHookPrefix: "WIP",
|
||||
AutoFetch: true,
|
||||
BranchLogCmd: "git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --",
|
||||
|
|
@ -373,6 +387,8 @@ func GetDefaultConfig() *UserConfig {
|
|||
NextItemAlt: "j",
|
||||
PrevPage: ",",
|
||||
NextPage: ".",
|
||||
ScrollLeft: "H",
|
||||
ScrollRight: "L",
|
||||
GotoTop: "<",
|
||||
GotoBottom: ">",
|
||||
PrevBlock: "<left>",
|
||||
|
|
@ -479,6 +495,7 @@ func GetDefaultConfig() *UserConfig {
|
|||
CheckoutCommit: "<space>",
|
||||
ResetCherryPick: "<c-R>",
|
||||
CopyCommitMessageToClipboard: "<c-y>",
|
||||
OpenLogMenu: "<c-l>",
|
||||
},
|
||||
Stash: KeybindingStashConfig{
|
||||
PopStash: "g",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ import (
|
|||
"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
|
||||
|
||||
func (gui *Gui) getSelectedLocalCommit() *models.Commit {
|
||||
|
|
@ -23,7 +26,7 @@ func (gui *Gui) getSelectedLocalCommit() *models.Commit {
|
|||
|
||||
func (gui *Gui) handleCommitSelect() error {
|
||||
state := gui.State.Panels.Commits
|
||||
if state.SelectedLineIdx > 290 && state.LimitCommits {
|
||||
if state.SelectedLineIdx > COMMIT_THRESHOLD && state.LimitCommits {
|
||||
state.LimitCommits = false
|
||||
go utils.Safe(func() {
|
||||
if err := gui.refreshCommitsWithLimit(); err != nil {
|
||||
|
|
@ -134,6 +137,7 @@ func (gui *Gui) refreshCommitsWithLimit() error {
|
|||
FilterPath: gui.State.Modes.Filtering.GetPath(),
|
||||
IncludeRebaseCommits: true,
|
||||
RefName: "HEAD",
|
||||
All: gui.State.ShowWholeGitGraph,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
|
|
@ -679,3 +683,87 @@ func (gui *Gui) handleCopySelectedCommitMessageToClipboard() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleOpenLogMenu() error {
|
||||
return gui.createMenu(gui.Tr.LogMenuTitle, []*menuItem{
|
||||
{
|
||||
displayString: gui.Tr.ToggleShowGitGraphAll,
|
||||
onPress: func() error {
|
||||
gui.State.ShowWholeGitGraph = !gui.State.ShowWholeGitGraph
|
||||
|
||||
if gui.State.ShowWholeGitGraph {
|
||||
gui.State.Panels.Commits.LimitCommits = false
|
||||
}
|
||||
|
||||
return gui.WithWaitingStatus(gui.Tr.LcLoadingCommits, func() error {
|
||||
return gui.refreshSidePanels(refreshOptions{mode: SYNC, scope: []RefreshableView{COMMITS}})
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
displayString: gui.Tr.ShowGitGraph,
|
||||
opensMenu: true,
|
||||
onPress: func() error {
|
||||
onSelect := func(value string) {
|
||||
gui.Config.GetUserConfig().Git.Log.ShowGraph = value
|
||||
gui.render()
|
||||
}
|
||||
return gui.createMenu(gui.Tr.LogMenuTitle, []*menuItem{
|
||||
{
|
||||
displayString: "always",
|
||||
onPress: func() error {
|
||||
onSelect("always")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
displayString: "never",
|
||||
onPress: func() error {
|
||||
onSelect("never")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
displayString: "when maximised",
|
||||
onPress: func() error {
|
||||
onSelect("when-maximised")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}, createMenuOptions{showCancel: true})
|
||||
},
|
||||
},
|
||||
{
|
||||
displayString: gui.Tr.SortCommits,
|
||||
opensMenu: true,
|
||||
onPress: func() error {
|
||||
onSelect := func(value string) error {
|
||||
gui.Config.GetUserConfig().Git.Log.Order = value
|
||||
return gui.WithWaitingStatus(gui.Tr.LcLoadingCommits, func() error {
|
||||
return gui.refreshSidePanels(refreshOptions{mode: SYNC, scope: []RefreshableView{COMMITS}})
|
||||
})
|
||||
}
|
||||
return gui.createMenu(gui.Tr.LogMenuTitle, []*menuItem{
|
||||
{
|
||||
displayString: "topological (topo-order)",
|
||||
onPress: func() error {
|
||||
return onSelect("topo-order")
|
||||
},
|
||||
},
|
||||
{
|
||||
displayString: "date-order",
|
||||
onPress: func() error {
|
||||
return onSelect("date-order")
|
||||
},
|
||||
},
|
||||
{
|
||||
displayString: "author-date-order",
|
||||
onPress: func() error {
|
||||
return onSelect("author-date-order")
|
||||
},
|
||||
},
|
||||
}, createMenuOptions{showCancel: true})
|
||||
},
|
||||
},
|
||||
}, createMenuOptions{showCancel: true})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,6 +399,8 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error
|
|||
return nil
|
||||
}
|
||||
|
||||
_ = oldView.SetOriginX(0)
|
||||
|
||||
if oldView == gui.Views.CommitFiles && newView != gui.Views.Main && newView != gui.Views.Secondary && newView != gui.Views.Search {
|
||||
gui.resetWindowForView(gui.Views.CommitFiles)
|
||||
if err := gui.deactivateContext(gui.State.Contexts.CommitFiles); err != nil {
|
||||
|
|
|
|||
|
|
@ -29,15 +29,6 @@ func (gui *Gui) getRemoteNames() []string {
|
|||
return result
|
||||
}
|
||||
|
||||
// func (gui *Gui) getRemoteUrls() []string {
|
||||
// result := make([]string, len(gui.State.Remotes))
|
||||
// for i, remote := range gui.State.Remotes {
|
||||
// result[i] = remote.Urls[0]
|
||||
// gui.GitCommand.GetRemotesToOwnersMap()
|
||||
// }
|
||||
// return result
|
||||
// }
|
||||
|
||||
func matchesToSuggestions(matches []string) []*types.Suggestion {
|
||||
suggestions := make([]*types.Suggestion, len(matches))
|
||||
for i, match := range matches {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
const HORIZONTAL_SCROLL_FACTOR = 3
|
||||
|
||||
// these views need to be re-rendered when the screen mode changes. The commits view,
|
||||
// for example, will show authorship information in half and full screen mode.
|
||||
func (gui *Gui) rerenderViewsWithScreenModeDependentContent() error {
|
||||
|
|
@ -114,7 +116,7 @@ func (gui *Gui) linesToScrollDown(view *gocui.View) int {
|
|||
|
||||
func (gui *Gui) scrollUpMain() error {
|
||||
if gui.canScrollMergePanel() {
|
||||
gui.State.Panels.Merging.UserScrolling = true
|
||||
gui.State.Panels.Merging.UserVerticalScrolling = true
|
||||
}
|
||||
|
||||
return gui.scrollUpView(gui.Views.Main)
|
||||
|
|
@ -122,12 +124,33 @@ func (gui *Gui) scrollUpMain() error {
|
|||
|
||||
func (gui *Gui) scrollDownMain() error {
|
||||
if gui.canScrollMergePanel() {
|
||||
gui.State.Panels.Merging.UserScrolling = true
|
||||
gui.State.Panels.Merging.UserVerticalScrolling = true
|
||||
}
|
||||
|
||||
return gui.scrollDownView(gui.Views.Main)
|
||||
}
|
||||
|
||||
func (gui *Gui) scrollLeftMain() error {
|
||||
gui.scrollLeft(gui.Views.Main)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) scrollRightMain() error {
|
||||
gui.scrollRight(gui.Views.Main)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) scrollLeft(view *gocui.View) {
|
||||
newOriginX := utils.Max(view.OriginX()-view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR, 0)
|
||||
_ = view.SetOriginX(newOriginX)
|
||||
}
|
||||
|
||||
func (gui *Gui) scrollRight(view *gocui.View) {
|
||||
_ = view.SetOriginX(view.OriginX() + view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR)
|
||||
}
|
||||
|
||||
func (gui *Gui) scrollUpSecondary() error {
|
||||
return gui.scrollUpView(gui.Views.Secondary)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/filtering"
|
||||
"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/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||
|
|
@ -145,9 +146,9 @@ type LblPanelState struct {
|
|||
type MergingPanelState struct {
|
||||
*mergeconflicts.State
|
||||
|
||||
// UserScrolling tells us if the user has started scrolling through the file themselves
|
||||
// UserVerticalScrolling tells us if the user has started scrolling through the file themselves
|
||||
// in which case we won't auto-scroll to a conflict.
|
||||
UserScrolling bool
|
||||
UserVerticalScrolling bool
|
||||
}
|
||||
|
||||
type filePanelState struct {
|
||||
|
|
@ -315,6 +316,8 @@ type guiState struct {
|
|||
RetainOriginalDir bool
|
||||
IsRefreshingFiles bool
|
||||
Searching searchingState
|
||||
// if this is true, we'll load our commits using `git log --all`
|
||||
ShowWholeGitGraph bool
|
||||
ScreenMode WindowMaximisation
|
||||
Ptmx *os.File
|
||||
PrevMainWidth int
|
||||
|
|
@ -400,7 +403,7 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) {
|
|||
Remotes: &remotePanelState{listPanelState{SelectedLineIdx: 0}},
|
||||
RemoteBranches: &remoteBranchesState{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}},
|
||||
SubCommits: &subCommitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, refName: ""},
|
||||
CommitFiles: &commitFilesPanelState{listPanelState: listPanelState{SelectedLineIdx: -1}, refName: ""},
|
||||
|
|
@ -408,8 +411,8 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) {
|
|||
Menu: &menuPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, OnPress: nil},
|
||||
Suggestions: &suggestionsPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}},
|
||||
Merging: &MergingPanelState{
|
||||
State: mergeconflicts.NewState(),
|
||||
UserScrolling: false,
|
||||
State: mergeconflicts.NewState(),
|
||||
UserVerticalScrolling: false,
|
||||
},
|
||||
},
|
||||
GithubState: &GithubState{},
|
||||
|
|
@ -466,8 +469,8 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *oscom
|
|||
|
||||
var RuneReplacements = map[rune]string{
|
||||
// for the commit graph
|
||||
'⏣': "M",
|
||||
'⎔': "o",
|
||||
graph.MergeSymbol: "M",
|
||||
graph.CommitSymbol: "o",
|
||||
}
|
||||
|
||||
// Run setup the gui with keybindings and start the mainloop
|
||||
|
|
|
|||
|
|
@ -724,6 +724,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
Handler: gui.handleFetchRemote,
|
||||
Description: gui.Tr.LcFetchRemote,
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)},
|
||||
Key: gui.getKey(config.Commits.OpenLogMenu),
|
||||
Handler: gui.handleOpenLogMenu,
|
||||
Description: gui.Tr.LcOpenLogMenu,
|
||||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)},
|
||||
|
|
@ -1426,6 +1434,20 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollDownMain,
|
||||
},
|
||||
{
|
||||
ViewName: "main",
|
||||
Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY), string(MAIN_MERGING_CONTEXT_KEY)},
|
||||
Key: gui.getKey(config.Universal.ScrollLeft),
|
||||
Handler: gui.scrollLeftMain,
|
||||
Description: gui.Tr.LcScrollLeft,
|
||||
},
|
||||
{
|
||||
ViewName: "main",
|
||||
Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY), string(MAIN_MERGING_CONTEXT_KEY)},
|
||||
Key: gui.getKey(config.Universal.ScrollRight),
|
||||
Handler: gui.scrollRightMain,
|
||||
Description: gui.Tr.LcScrollRight,
|
||||
},
|
||||
{
|
||||
ViewName: "main",
|
||||
Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)},
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ func (gui *Gui) focusSelection(state *LblPanelState) error {
|
|||
newOrigin := state.CalculateOrigin(origin, bufferHeight)
|
||||
|
||||
gui.g.Update(func(*gocui.Gui) error {
|
||||
if err := stagingView.SetOrigin(0, newOrigin); err != nil {
|
||||
if err := stagingView.SetOriginY(newOrigin); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package gui
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
type ListContext struct {
|
||||
|
|
@ -14,6 +16,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)
|
||||
SelectedItem func() (ListItem, bool)
|
||||
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
|
||||
|
||||
|
|
@ -26,6 +32,8 @@ type IListContext interface {
|
|||
OnRender() error
|
||||
handlePrevLine() error
|
||||
handleNextLine() error
|
||||
handleScrollLeft() error
|
||||
handleScrollRight() error
|
||||
handleLineChange(change int) error
|
||||
handleNextPage() error
|
||||
handleGotoTop() error
|
||||
|
|
@ -60,10 +68,17 @@ type ListItem interface {
|
|||
func (self *ListContext) FocusLine() {
|
||||
view, err := self.Gui.g.View(self.ViewName)
|
||||
if err != nil {
|
||||
// ignoring error for now
|
||||
return
|
||||
}
|
||||
|
||||
view.FocusPoint(0, self.GetPanelState().GetSelectedLineIdx())
|
||||
// we need a way of knowing whether we've rendered to the view yet.
|
||||
view.FocusPoint(view.OriginX(), 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())
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +121,13 @@ func (self *ListContext) HandleFocusLost() error {
|
|||
return self.OnFocusLost()
|
||||
}
|
||||
|
||||
view, err := self.Gui.g.View(self.ViewName)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = view.SetOriginX(0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -139,8 +161,36 @@ func (self *ListContext) handleNextLine() error {
|
|||
return self.handleLineChange(1)
|
||||
}
|
||||
|
||||
func (self *ListContext) handleScrollLeft() error {
|
||||
return self.scroll(self.Gui.scrollLeft)
|
||||
}
|
||||
|
||||
func (self *ListContext) handleScrollRight() error {
|
||||
return self.scroll(self.Gui.scrollRight)
|
||||
}
|
||||
|
||||
func (self *ListContext) scroll(scrollFunc func(*gocui.View)) error {
|
||||
if self.ignoreKeybinding() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get the view, move the origin
|
||||
view, err := self.Gui.g.View(self.ViewName)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
scrollFunc(view)
|
||||
|
||||
return self.HandleFocus()
|
||||
}
|
||||
|
||||
func (self *ListContext) ignoreKeybinding() bool {
|
||||
return !self.Gui.isPopupPanel(self.ViewName) && self.Gui.popupPanelFocused()
|
||||
}
|
||||
|
||||
func (self *ListContext) handleLineChange(change int) error {
|
||||
if !self.Gui.isPopupPanel(self.ViewName) && self.Gui.popupPanelFocused() {
|
||||
if self.ignoreKeybinding() {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +234,7 @@ func (self *ListContext) handlePrevPage() error {
|
|||
}
|
||||
|
||||
func (self *ListContext) handleClick() error {
|
||||
if !self.Gui.isPopupPanel(self.ViewName) && self.Gui.popupPanelFocused() {
|
||||
if self.ignoreKeybinding() {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
|
|
@ -158,21 +160,48 @@ func (gui *Gui) branchCommitsListContext() IListContext {
|
|||
OnClickSelectedItem: gui.handleViewCommitFiles,
|
||||
Gui: gui,
|
||||
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(
|
||||
gui.State.Commits,
|
||||
gui.State.ScreenMode != SCREEN_NORMAL,
|
||||
gui.cherryPickedCommitShaMap(),
|
||||
gui.State.Modes.Diffing.Ref,
|
||||
parseEmoji,
|
||||
selectedCommitSha,
|
||||
startIdx,
|
||||
length,
|
||||
gui.shouldShowGraph(),
|
||||
)
|
||||
},
|
||||
SelectedItem: func() (ListItem, bool) {
|
||||
item := gui.getSelectedLocalCommit()
|
||||
return item, item != nil
|
||||
},
|
||||
RenderSelection: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) shouldShowGraph() bool {
|
||||
value := gui.Config.GetUserConfig().Git.Log.ShowGraph
|
||||
switch value {
|
||||
case "always":
|
||||
return true
|
||||
case "never":
|
||||
return false
|
||||
case "when-maximised":
|
||||
return gui.State.ScreenMode != SCREEN_NORMAL
|
||||
}
|
||||
|
||||
log.Fatalf("Unknown value for git.log.showGraph: %s. Expected one of: 'always', 'never', 'when-maximised'", value)
|
||||
return false
|
||||
}
|
||||
|
||||
func (gui *Gui) reflogCommitsListContext() IListContext {
|
||||
parseEmoji := gui.Config.GetUserConfig().Git.ParseEmoji
|
||||
return &ListContext{
|
||||
|
|
@ -216,18 +245,30 @@ func (gui *Gui) subCommitsListContext() IListContext {
|
|||
OnFocus: gui.handleSubCommitSelect,
|
||||
Gui: gui,
|
||||
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(
|
||||
gui.State.SubCommits,
|
||||
gui.State.ScreenMode != SCREEN_NORMAL,
|
||||
gui.cherryPickedCommitShaMap(),
|
||||
gui.State.Modes.Diffing.Ref,
|
||||
parseEmoji,
|
||||
selectedCommitSha,
|
||||
0,
|
||||
len(gui.State.SubCommits),
|
||||
gui.shouldShowGraph(),
|
||||
)
|
||||
},
|
||||
SelectedItem: func() (ListItem, bool) {
|
||||
item := gui.getSelectedSubCommit()
|
||||
return item, item != nil
|
||||
},
|
||||
RenderSelection: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -362,6 +403,8 @@ func (gui *Gui) getListContextKeyBindings() []*Binding {
|
|||
{ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.GotoTop), Modifier: gocui.ModNone, Handler: listContext.handleGotoTop, Description: gui.Tr.LcGotoTop},
|
||||
{ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: listContext.handleNextLine},
|
||||
{ViewName: listContext.GetViewName(), Contexts: []string{string(listContext.GetKey())}, Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: listContext.handleClick},
|
||||
{ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: listContext.handleScrollLeft},
|
||||
{ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: listContext.handleScrollRight},
|
||||
}...)
|
||||
|
||||
// the commits panel needs to lazyload things so it has a couple of its own handlers
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
|
@ -13,6 +14,8 @@ type menuItem struct {
|
|||
displayString string
|
||||
displayStrings []string
|
||||
onPress func() error
|
||||
// only applies when displayString is used
|
||||
opensMenu bool
|
||||
}
|
||||
|
||||
// every item in a list context needs an ID
|
||||
|
|
@ -65,8 +68,16 @@ func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions cr
|
|||
|
||||
stringArrays := make([][]string, len(items))
|
||||
for i, item := range items {
|
||||
if item.opensMenu && item.displayStrings != nil {
|
||||
return errors.New("Message for the developer of this app: you've set opensMenu with displaystrings on the menu panel. Bad developer!. Apologies, user")
|
||||
}
|
||||
|
||||
if item.displayStrings == nil {
|
||||
stringArrays[i] = []string{item.displayString}
|
||||
styledStr := item.displayString
|
||||
if item.opensMenu {
|
||||
styledStr = opensMenuStyle(styledStr)
|
||||
}
|
||||
stringArrays[i] = []string{styledStr}
|
||||
} else {
|
||||
stringArrays[i] = item.displayStrings
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ func (gui *Gui) catSelectedFile() (string, error) {
|
|||
}
|
||||
|
||||
func (gui *Gui) scrollToConflict() error {
|
||||
if gui.State.Panels.Merging.UserScrolling {
|
||||
if gui.State.Panels.Merging.UserVerticalScrolling {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -315,5 +315,5 @@ func (gui *Gui) withMergeConflictLock(f func() error) error {
|
|||
}
|
||||
|
||||
func (gui *Gui) takeOverMergeConflictScrolling() {
|
||||
gui.State.Panels.Merging.UserScrolling = false
|
||||
gui.State.Panels.Merging.UserVerticalScrolling = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,12 +36,16 @@ func (gui *Gui) getBindings(v *gocui.View) []*Binding {
|
|||
|
||||
func (gui *Gui) displayDescription(binding *Binding) string {
|
||||
if binding.OpensMenu {
|
||||
return style.FgMagenta.Sprintf("%s...", binding.Description)
|
||||
return opensMenuStyle(binding.Description)
|
||||
}
|
||||
|
||||
return style.FgCyan.Sprint(binding.Description)
|
||||
}
|
||||
|
||||
func opensMenuStyle(str string) string {
|
||||
return style.FgMagenta.Sprintf("%s...", str)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreateOptionsMenu() error {
|
||||
view := gui.g.CurrentView()
|
||||
if view == nil {
|
||||
|
|
|
|||
|
|
@ -2,120 +2,163 @@ package presentation
|
|||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"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/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/kyokomi/emoji/v2"
|
||||
)
|
||||
|
||||
func GetCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaMap map[string]bool, diffName string, parseEmoji bool) [][]string {
|
||||
lines := make([][]string, len(commits))
|
||||
type pipeSetCacheKey struct {
|
||||
commitSha string
|
||||
commitCount int
|
||||
}
|
||||
|
||||
var displayFunc func(*models.Commit, map[string]bool, bool, bool) []string
|
||||
if fullDescription {
|
||||
displayFunc = getFullDescriptionDisplayStringsForCommit
|
||||
var pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe)
|
||||
var mutex sync.Mutex
|
||||
|
||||
func GetCommitListDisplayStrings(
|
||||
commits []*models.Commit,
|
||||
fullDescription bool,
|
||||
cherryPickedCommitShaMap map[string]bool,
|
||||
diffName string,
|
||||
parseEmoji bool,
|
||||
selectedCommitSha string,
|
||||
startIdx int,
|
||||
length int,
|
||||
showGraph bool,
|
||||
) [][]string {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if len(commits) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// when dealing with things like filtered commits.
|
||||
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
|
||||
}
|
||||
|
||||
if startIdx > len(commits) {
|
||||
return nil
|
||||
}
|
||||
end := startIdx + length
|
||||
if end > len(commits)-1 {
|
||||
end = len(commits) - 1
|
||||
}
|
||||
|
||||
filteredCommits := commits[startIdx : end+1]
|
||||
|
||||
var getGraphLine func(int) string
|
||||
if showGraph {
|
||||
filteredPipeSets := pipeSets[startIdx : end+1]
|
||||
graphLines := graph.RenderAux(filteredPipeSets, filteredCommits, selectedCommitSha)
|
||||
getGraphLine = func(idx int) string { return graphLines[idx] }
|
||||
} else {
|
||||
displayFunc = getDisplayStringsForCommit
|
||||
getGraphLine = func(idx int) string { return "" }
|
||||
}
|
||||
|
||||
for i := range commits {
|
||||
diffed := commits[i].Sha == diffName
|
||||
lines[i] = displayFunc(commits[i], cherryPickedCommitShaMap, diffed, parseEmoji)
|
||||
lines := make([][]string, 0, len(filteredCommits))
|
||||
for i, commit := range filteredCommits {
|
||||
lines = append(lines, displayCommit(commit, cherryPickedCommitShaMap, diffName, parseEmoji, getGraphLine(i), fullDescription))
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
func getFullDescriptionDisplayStringsForCommit(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
|
||||
}
|
||||
func displayCommit(
|
||||
commit *models.Commit,
|
||||
cherryPickedCommitShaMap map[string]bool,
|
||||
diffName string,
|
||||
parseEmoji bool,
|
||||
graphLine string,
|
||||
fullDescription bool,
|
||||
) []string {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
shaColor := getShaColor(commit, diffName, cherryPickedCommitShaMap)
|
||||
|
||||
actionString := ""
|
||||
tagString := ""
|
||||
if c.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, " ")) + " "
|
||||
if commit.Action != "" {
|
||||
actionString = actionColorMap(commit.Action).Sprint(commit.Action) + " "
|
||||
}
|
||||
|
||||
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 {
|
||||
name = emoji.Sprint(name)
|
||||
}
|
||||
|
||||
return []string{
|
||||
shaColor.Sprint(c.ShortSha()),
|
||||
authors.ShortAuthor(c.Author),
|
||||
actionString + tagString + theme.DefaultTextColor.Sprint(name),
|
||||
authorFunc := authors.ShortAuthor
|
||||
if fullDescription {
|
||||
authorFunc = authors.LongAuthor
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package graph
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/gookit/color"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
)
|
||||
|
||||
const mergeSymbol = '⏣'
|
||||
const commitSymbol = '⎔'
|
||||
const MergeSymbol = '⏣'
|
||||
const CommitSymbol = '◯'
|
||||
|
||||
type cellType int
|
||||
|
||||
|
|
@ -22,18 +26,18 @@ type Cell struct {
|
|||
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
|
||||
|
||||
first, second := getBoxDrawingChars(up, down, left, right)
|
||||
var adjustedFirst rune
|
||||
var adjustedFirst string
|
||||
switch cell.cellType {
|
||||
case CONNECTION:
|
||||
adjustedFirst = first
|
||||
case COMMIT:
|
||||
adjustedFirst = commitSymbol
|
||||
adjustedFirst = string(CommitSymbol)
|
||||
case MERGE:
|
||||
adjustedFirst = mergeSymbol
|
||||
adjustedFirst = string(MergeSymbol)
|
||||
}
|
||||
|
||||
var rightStyle *style.TextStyle
|
||||
|
|
@ -47,13 +51,46 @@ func (cell *Cell) render() string {
|
|||
// assert on the style of a space given a space has no styling (assuming we
|
||||
// stick to only using foreground styles)
|
||||
var styledSecondChar string
|
||||
if second == ' ' {
|
||||
if second == " " {
|
||||
styledSecondChar = " "
|
||||
} 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() {
|
||||
|
|
@ -102,39 +139,39 @@ func (cell *Cell) setType(cellType cellType) *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 {
|
||||
return '│', '─'
|
||||
return "│", "─"
|
||||
} else if up && down && left && !right {
|
||||
return '│', ' '
|
||||
return "│", " "
|
||||
} else if up && down && !left && right {
|
||||
return '│', '─'
|
||||
return "│", "─"
|
||||
} else if up && down && !left && !right {
|
||||
return '│', ' '
|
||||
return "│", " "
|
||||
} else if up && !down && left && right {
|
||||
return '┴', '─'
|
||||
return "┴", "─"
|
||||
} else if up && !down && left && !right {
|
||||
return '╯', ' '
|
||||
return "╯", " "
|
||||
} else if up && !down && !left && right {
|
||||
return '╰', '─'
|
||||
return "╰", "─"
|
||||
} else if up && !down && !left && !right {
|
||||
return '╵', ' '
|
||||
return "╵", " "
|
||||
} else if !up && down && left && right {
|
||||
return '┬', '─'
|
||||
return "┬", "─"
|
||||
} else if !up && down && left && !right {
|
||||
return '╮', ' '
|
||||
return "╮", " "
|
||||
} else if !up && down && !left && right {
|
||||
return '╭', '─'
|
||||
return "╭", "─"
|
||||
} else if !up && down && !left && !right {
|
||||
return '╷', ' '
|
||||
return "╷", " "
|
||||
} else if !up && !down && left && right {
|
||||
return '─', '─'
|
||||
return "─", "─"
|
||||
} else if !up && !down && left && !right {
|
||||
return '─', ' '
|
||||
return "─", " "
|
||||
} else if !up && !down && !left && right {
|
||||
return '╶', '─'
|
||||
return "╶", "─"
|
||||
} else if !up && !down && !left && !right {
|
||||
return ' ', ' '
|
||||
return " ", " "
|
||||
} else {
|
||||
panic("should not be possible")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package graph
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -29,7 +30,7 @@ type Pipe struct {
|
|||
|
||||
var highlightStyle = style.FgLightWhite.SetBold()
|
||||
|
||||
func ContainsCommitSha(pipes []Pipe, sha string) bool {
|
||||
func ContainsCommitSha(pipes []*Pipe, sha string) bool {
|
||||
for _, pipe := range pipes {
|
||||
if equalHashes(pipe.fromSha, sha) {
|
||||
return true
|
||||
|
|
@ -57,14 +58,14 @@ func RenderCommitGraph(commits []*models.Commit, selectedCommitSha string, getSt
|
|||
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 {
|
||||
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 {
|
||||
pipes = getNextPipes(pipes, commit, getStyle)
|
||||
pipeSets = append(pipeSets, pipes)
|
||||
|
|
@ -73,29 +74,51 @@ func GetPipeSets(commits []*models.Commit, getStyle func(c *models.Commit) style
|
|||
return pipeSets
|
||||
}
|
||||
|
||||
func RenderAux(pipeSets [][]Pipe, commits []*models.Commit, selectedCommitSha string) []string {
|
||||
lines := make([]string, len(pipeSets))
|
||||
func RenderAux(pipeSets [][]*Pipe, commits []*models.Commit, selectedCommitSha string) []string {
|
||||
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.Add(len(pipeSets))
|
||||
for i, pipeSet := range pipeSets {
|
||||
wg.Add(maxProcs)
|
||||
|
||||
for i := 0; i < maxProcs; i++ {
|
||||
i := i
|
||||
pipeSet := pipeSet
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
var prevCommit *models.Commit
|
||||
if i > 0 {
|
||||
prevCommit = commits[i-1]
|
||||
from := i * perProc
|
||||
to := (i + 1) * perProc
|
||||
if i == maxProcs-1 {
|
||||
to = len(pipeSets)
|
||||
}
|
||||
line := renderPipeSet(pipeSet, selectedCommitSha, prevCommit)
|
||||
lines[i] = line
|
||||
innerLines := make([]string, 0, to-from)
|
||||
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()
|
||||
|
||||
for _, chunk := range chunks {
|
||||
lines = append(lines, chunk...)
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *models.Commit) style.TextStyle) []Pipe {
|
||||
currentPipes := make([]Pipe, 0, len(prevPipes))
|
||||
func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *models.Commit) style.TextStyle) []*Pipe {
|
||||
currentPipes := make([]*Pipe, 0, len(prevPipes))
|
||||
maxPos := 0
|
||||
for _, pipe := range prevPipes {
|
||||
// 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)
|
||||
}
|
||||
|
||||
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.
|
||||
// (this only happens when we're doing `git log --all`). These will be tacked onto the far end.
|
||||
pos := maxPos + 1
|
||||
|
|
@ -124,7 +147,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||
traversedSpots := make(map[int]bool)
|
||||
|
||||
if len(commit.Parents) > 0 {
|
||||
newPipes = append(newPipes, Pipe{
|
||||
newPipes = append(newPipes, &Pipe{
|
||||
fromPos: pos,
|
||||
toPos: pos,
|
||||
fromSha: commit.Sha,
|
||||
|
|
@ -177,7 +200,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||
for _, pipe := range currentPipes {
|
||||
if equalHashes(pipe.toSha, commit.Sha) {
|
||||
// terminating here
|
||||
newPipes = append(newPipes, Pipe{
|
||||
newPipes = append(newPipes, &Pipe{
|
||||
fromPos: pipe.toPos,
|
||||
toPos: pos,
|
||||
fromSha: pipe.fromSha,
|
||||
|
|
@ -189,7 +212,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||
} else if pipe.toPos < pos {
|
||||
// continuing here
|
||||
availablePos := getNextAvailablePosForContinuingPipe()
|
||||
newPipes = append(newPipes, Pipe{
|
||||
newPipes = append(newPipes, &Pipe{
|
||||
fromPos: pipe.toPos,
|
||||
toPos: availablePos,
|
||||
fromSha: pipe.fromSha,
|
||||
|
|
@ -205,7 +228,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||
for _, parent := range commit.Parents[1:] {
|
||||
availablePos := getNextAvailablePosForNewPipe()
|
||||
// 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,
|
||||
toPos: availablePos,
|
||||
fromSha: commit.Sha,
|
||||
|
|
@ -229,7 +252,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||
last = i
|
||||
}
|
||||
}
|
||||
newPipes = append(newPipes, Pipe{
|
||||
newPipes = append(newPipes, &Pipe{
|
||||
fromPos: pipe.toPos,
|
||||
toPos: last,
|
||||
fromSha: pipe.fromSha,
|
||||
|
|
@ -253,7 +276,7 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode
|
|||
}
|
||||
|
||||
func renderPipeSet(
|
||||
pipes []Pipe,
|
||||
pipes []*Pipe,
|
||||
selectedCommitSha string,
|
||||
prevCommit *models.Commit,
|
||||
) string {
|
||||
|
|
@ -279,7 +302,7 @@ func renderPipeSet(
|
|||
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()
|
||||
right := pipe.right()
|
||||
|
||||
|
|
@ -313,9 +336,9 @@ func renderPipeSet(
|
|||
|
||||
// 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.
|
||||
selectedPipes := []Pipe{}
|
||||
selectedPipes := []*Pipe{}
|
||||
// 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 {
|
||||
if highlight && equalHashes(pipe.fromSha, selectedCommitSha) {
|
||||
|
|
@ -356,11 +379,13 @@ func renderPipeSet(
|
|||
|
||||
cells[commitPos].setType(cType)
|
||||
|
||||
renderedCells := make([]string, len(cells))
|
||||
for i, cell := range cells {
|
||||
renderedCells[i] = cell.render()
|
||||
// using a string builder here for the sake of performance
|
||||
writer := &strings.Builder{}
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package graph
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gookit/color"
|
||||
"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/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -42,20 +45,20 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
{Sha: "D", Parents: []string{"G"}},
|
||||
},
|
||||
expectedOutput: `
|
||||
1 ⎔
|
||||
2 ⎔
|
||||
3 ⎔
|
||||
1 ◯
|
||||
2 ◯
|
||||
3 ◯
|
||||
4 ⏣─╮
|
||||
7 │ ⎔
|
||||
5 ⎔─╯
|
||||
8 ⎔
|
||||
7 │ ◯
|
||||
5 ◯─╯
|
||||
8 ◯
|
||||
9 ⏣─╮
|
||||
B │ ⎔
|
||||
D │ ⎔
|
||||
A ⎔ │
|
||||
E ⎔ │
|
||||
F ⎔ │
|
||||
D ⎔─╯`,
|
||||
B │ ◯
|
||||
D │ ◯
|
||||
A ◯ │
|
||||
E ◯ │
|
||||
F ◯ │
|
||||
D ◯─╯`,
|
||||
},
|
||||
{
|
||||
name: "with a path that has room to move to the left",
|
||||
|
|
@ -68,12 +71,12 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
{Sha: "6", Parents: []string{"7"}},
|
||||
},
|
||||
expectedOutput: `
|
||||
1 ⎔
|
||||
1 ◯
|
||||
2 ⏣─╮
|
||||
4 │ ⏣─╮
|
||||
3 ⎔─╯ │
|
||||
5 ⎔───╯
|
||||
6 ⎔`,
|
||||
3 ◯─╯ │
|
||||
5 ◯───╯
|
||||
6 ◯`,
|
||||
},
|
||||
{
|
||||
name: "with a new commit",
|
||||
|
|
@ -87,13 +90,13 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
{Sha: "6", Parents: []string{"7"}},
|
||||
},
|
||||
expectedOutput: `
|
||||
1 ⎔
|
||||
1 ◯
|
||||
2 ⏣─╮
|
||||
4 │ ⏣─╮
|
||||
Z │ │ │ ⎔
|
||||
3 ⎔─╯ │ │
|
||||
5 ⎔───╯ │
|
||||
6 ⎔ ╭───╯`,
|
||||
Z │ │ │ ◯
|
||||
3 ◯─╯ │ │
|
||||
5 ◯───╯ │
|
||||
6 ◯ ╭───╯`,
|
||||
},
|
||||
{
|
||||
name: "with a path that has room to move to the left and continues",
|
||||
|
|
@ -106,12 +109,12 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
{Sha: "7", Parents: []string{"11"}},
|
||||
},
|
||||
expectedOutput: `
|
||||
1 ⎔
|
||||
1 ◯
|
||||
2 ⏣─╮
|
||||
3 ⏣─│─╮
|
||||
5 ⏣─│─│─╮
|
||||
4 │ ⎔─╯ │
|
||||
7 ⎔─╯ ╭─╯`,
|
||||
4 │ ◯─╯ │
|
||||
7 ◯─╯ ╭─╯`,
|
||||
},
|
||||
{
|
||||
name: "with a path that has room to move to the left and continues",
|
||||
|
|
@ -125,13 +128,13 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
{Sha: "B", Parents: []string{"C"}},
|
||||
},
|
||||
expectedOutput: `
|
||||
1 ⎔
|
||||
1 ◯
|
||||
2 ⏣─╮
|
||||
3 ⏣─│─╮
|
||||
5 ⏣─│─│─╮
|
||||
7 ⏣─│─│─│─╮
|
||||
4 ⎔─┴─╯ │ │
|
||||
B ⎔ ╭───╯ │`,
|
||||
4 ◯─┴─╯ │ │
|
||||
B ◯ ╭───╯ │`,
|
||||
},
|
||||
{
|
||||
name: "with a path that has room to move to the left and continues",
|
||||
|
|
@ -144,10 +147,10 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
},
|
||||
expectedOutput: `
|
||||
1 ⏣─╮
|
||||
3 │ ⎔
|
||||
3 │ ◯
|
||||
2 ⏣─│
|
||||
4 ⏣─│─╮
|
||||
6 ⎔ │ │`,
|
||||
6 ◯ │ │`,
|
||||
},
|
||||
{
|
||||
name: "new merge path fills gap before continuing path on right",
|
||||
|
|
@ -160,10 +163,10 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
},
|
||||
expectedOutput: `
|
||||
1 ⏣─┬─┬─╮
|
||||
4 │ │ ⎔ │
|
||||
2 ⎔─│─╯ │
|
||||
4 │ │ ◯ │
|
||||
2 ◯─│─╯ │
|
||||
A ⏣─│─╮ │
|
||||
B │ │ ⎔ │`,
|
||||
B │ │ ◯ │`,
|
||||
},
|
||||
{
|
||||
name: "with a path that has room to move to the left and continues",
|
||||
|
|
@ -178,14 +181,14 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
{Sha: "C", Parents: []string{"D"}},
|
||||
},
|
||||
expectedOutput: `
|
||||
1 ⎔
|
||||
1 ◯
|
||||
2 ⏣─╮
|
||||
3 ⏣─│─╮
|
||||
5 ⏣─│─│─╮
|
||||
7 ⏣─│─│─│─╮
|
||||
4 ⎔─┴─╯ │ │
|
||||
B ⎔ ╭───╯ │
|
||||
C ⎔ │ ╭───╯`,
|
||||
4 ◯─┴─╯ │ │
|
||||
B ◯ ╭───╯ │
|
||||
C ◯ │ ╭───╯`,
|
||||
},
|
||||
{
|
||||
name: "with a path that has room to move to the left and continues",
|
||||
|
|
@ -202,16 +205,16 @@ func TestRenderCommitGraph(t *testing.T) {
|
|||
{Sha: "D", Parents: []string{"F"}},
|
||||
},
|
||||
expectedOutput: `
|
||||
1 ⎔
|
||||
1 ◯
|
||||
2 ⏣─╮
|
||||
3 ⏣─│─╮
|
||||
5 ⏣─│─│─╮
|
||||
7 ⏣─│─│─│─╮
|
||||
8 ⏣─│─│─│─│─╮
|
||||
4 ⎔─┴─╯ │ │ │
|
||||
B ⎔ ╭───╯ │ │
|
||||
C ⎔ │ ╭───╯ │
|
||||
D ⎔ │ │ ╭───╯`,
|
||||
4 ◯─┴─╯ │ │ │
|
||||
B ◯ ╭───╯ │ │
|
||||
C ◯ │ ╭───╯ │
|
||||
D ◯ │ │ ╭───╯`,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -253,7 +256,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
name string
|
||||
pipes []Pipe
|
||||
pipes []*Pipe
|
||||
commit *models.Commit
|
||||
prevCommit *models.Commit
|
||||
expectedStr string
|
||||
|
|
@ -261,27 +264,27 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "single cell",
|
||||
pipes: []Pipe{
|
||||
pipes: []*Pipe{
|
||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: TERMINATES, style: cyan},
|
||||
{fromPos: 0, toPos: 0, fromSha: "b", toSha: "c", kind: STARTS, style: green},
|
||||
},
|
||||
prevCommit: &models.Commit{Sha: "a"},
|
||||
expectedStr: "⎔",
|
||||
expectedStr: "◯",
|
||||
expectedStyles: []style.TextStyle{green},
|
||||
},
|
||||
{
|
||||
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: "selected", toSha: "c", kind: STARTS, style: green},
|
||||
},
|
||||
prevCommit: &models.Commit{Sha: "a"},
|
||||
expectedStr: "⎔",
|
||||
expectedStr: "◯",
|
||||
expectedStyles: []style.TextStyle{highlightStyle},
|
||||
},
|
||||
{
|
||||
name: "terminating hook and starting hook, selected",
|
||||
pipes: []Pipe{
|
||||
pipes: []*Pipe{
|
||||
{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: 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",
|
||||
pipes: []Pipe{
|
||||
name: "terminating hook and starting hook, prioritise the terminating one",
|
||||
pipes: []*Pipe{
|
||||
{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: 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",
|
||||
pipes: []Pipe{
|
||||
pipes: []*Pipe{
|
||||
{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: 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",
|
||||
pipes: []Pipe{
|
||||
pipes: []*Pipe{
|
||||
{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: 1, toPos: 1, fromSha: "b1", toSha: "b2", kind: CONTINUES, style: magenta},
|
||||
|
|
@ -339,21 +342,21 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
},
|
||||
{
|
||||
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: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
||||
{fromPos: 1, toPos: 0, fromSha: "b1", toSha: "a2", kind: TERMINATES, style: magenta},
|
||||
{fromPos: 2, toPos: 0, fromSha: "c1", toSha: "a2", kind: TERMINATES, style: green},
|
||||
},
|
||||
prevCommit: &models.Commit{Sha: "a1"},
|
||||
expectedStr: "⎔─┴─╯",
|
||||
expectedStr: "◯─┴─╯",
|
||||
expectedStyles: []style.TextStyle{
|
||||
yellow, magenta, magenta, green, green,
|
||||
},
|
||||
},
|
||||
{
|
||||
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: "a2", toSha: "a3", 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",
|
||||
pipes: []Pipe{
|
||||
pipes: []*Pipe{
|
||||
{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: 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",
|
||||
pipes: []Pipe{
|
||||
pipes: []*Pipe{
|
||||
{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: 1, fromSha: "a2", toSha: "b3", kind: STARTS, style: yellow},
|
||||
|
|
@ -398,44 +401,44 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
},
|
||||
{
|
||||
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: "a2", toSha: "a3", kind: STARTS, style: yellow},
|
||||
},
|
||||
prevCommit: &models.Commit{Sha: "selected"},
|
||||
expectedStr: "⎔",
|
||||
expectedStr: "◯",
|
||||
expectedStyles: []style.TextStyle{
|
||||
yellow,
|
||||
},
|
||||
},
|
||||
{
|
||||
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: 1, toPos: 1, fromSha: "selected", toSha: "b3", kind: CONTINUES, style: red},
|
||||
},
|
||||
prevCommit: &models.Commit{Sha: "selected"},
|
||||
expectedStr: "⎔ │",
|
||||
expectedStr: "◯ │",
|
||||
expectedStyles: []style.TextStyle{
|
||||
highlightStyle, nothing, highlightStyle,
|
||||
},
|
||||
},
|
||||
{
|
||||
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: 1, toPos: 1, fromSha: "z1", toSha: "z3", kind: CONTINUES, style: green},
|
||||
{fromPos: 2, toPos: 2, fromSha: "selected", toSha: "b3", kind: CONTINUES, style: red},
|
||||
},
|
||||
prevCommit: &models.Commit{Sha: "selected"},
|
||||
expectedStr: "⎔ │ │",
|
||||
expectedStr: "◯ │ │",
|
||||
expectedStyles: []style.TextStyle{
|
||||
highlightStyle, nothing, green, nothing, highlightStyle,
|
||||
},
|
||||
},
|
||||
{
|
||||
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: "a2", toSha: "a3", 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) {
|
||||
tests := []struct {
|
||||
prevPipes []Pipe
|
||||
prevPipes []*Pipe
|
||||
commit *models.Commit
|
||||
expected []Pipe
|
||||
expected []*Pipe
|
||||
}{
|
||||
{
|
||||
prevPipes: []Pipe{
|
||||
prevPipes: []*Pipe{
|
||||
{fromPos: 0, toPos: 0, fromSha: "a", toSha: "b", kind: STARTS, style: style.FgDefault},
|
||||
},
|
||||
commit: &models.Commit{
|
||||
Sha: "b",
|
||||
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: "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: "b", toSha: "c", 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",
|
||||
Parents: []string{"e"},
|
||||
},
|
||||
expected: []Pipe{
|
||||
expected: []*Pipe{
|
||||
{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: "d", toSha: "e", kind: STARTS, style: style.FgDefault},
|
||||
|
|
@ -551,3 +524,47 @@ func TestGetNextPipes(t *testing.T) {
|
|||
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
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
|
|
@ -50,14 +51,19 @@ func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error
|
|||
|
||||
manager := gui.getManager(view)
|
||||
|
||||
ptmx, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
start := func() (*exec.Cmd, io.Reader) {
|
||||
ptmx, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
|
||||
gui.State.Ptmx = ptmx
|
||||
|
||||
return cmd, ptmx
|
||||
}
|
||||
|
||||
gui.State.Ptmx = ptmx
|
||||
onClose := func() {
|
||||
ptmx.Close()
|
||||
gui.State.Ptmx.Close()
|
||||
gui.State.Ptmx = nil
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +71,7 @@ func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error
|
|||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,19 +39,19 @@ func TestMerge(t *testing.T) {
|
|||
{
|
||||
"no color",
|
||||
nil,
|
||||
TextStyle{style: color.Style{}},
|
||||
TextStyle{Style: color.Style{}},
|
||||
"foo",
|
||||
},
|
||||
{
|
||||
"only fg color",
|
||||
[]TextStyle{FgRed},
|
||||
TextStyle{fg: &Color{basic: &fgRed}, style: color.Style{fgRed}},
|
||||
TextStyle{fg: &Color{basic: &fgRed}, Style: color.Style{fgRed}},
|
||||
"\x1b[31mfoo\x1b[0m",
|
||||
},
|
||||
{
|
||||
"only bg color",
|
||||
[]TextStyle{BgRed},
|
||||
TextStyle{bg: &Color{basic: &bgRed}, style: color.Style{bgRed}},
|
||||
TextStyle{bg: &Color{basic: &bgRed}, Style: color.Style{bgRed}},
|
||||
"\x1b[41mfoo\x1b[0m",
|
||||
},
|
||||
{
|
||||
|
|
@ -60,7 +60,7 @@ func TestMerge(t *testing.T) {
|
|||
TextStyle{
|
||||
fg: &Color{basic: &fgBlue},
|
||||
bg: &Color{basic: &bgRed},
|
||||
style: color.Style{fgBlue, bgRed},
|
||||
Style: color.Style{fgBlue, bgRed},
|
||||
},
|
||||
"\x1b[34;41mfoo\x1b[0m",
|
||||
},
|
||||
|
|
@ -69,7 +69,7 @@ func TestMerge(t *testing.T) {
|
|||
[]TextStyle{AttrBold},
|
||||
TextStyle{
|
||||
decoration: Decoration{bold: true},
|
||||
style: color.Style{color.OpBold},
|
||||
Style: color.Style{color.OpBold},
|
||||
},
|
||||
"\x1b[1mfoo\x1b[0m",
|
||||
},
|
||||
|
|
@ -81,7 +81,7 @@ func TestMerge(t *testing.T) {
|
|||
bold: true,
|
||||
underline: true,
|
||||
},
|
||||
style: color.Style{color.OpBold, color.OpUnderscore},
|
||||
Style: color.Style{color.OpBold, color.OpUnderscore},
|
||||
},
|
||||
"\x1b[1;4mfoo\x1b[0m",
|
||||
},
|
||||
|
|
@ -95,7 +95,7 @@ func TestMerge(t *testing.T) {
|
|||
bold: 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",
|
||||
},
|
||||
|
|
@ -104,7 +104,7 @@ func TestMerge(t *testing.T) {
|
|||
[]TextStyle{New().SetFg(rgbPink)},
|
||||
TextStyle{
|
||||
fg: &rgbPink,
|
||||
style: color.NewRGBStyle(rgbPinkLib).SetOpts(color.Opts{}),
|
||||
Style: color.NewRGBStyle(rgbPinkLib).SetOpts(color.Opts{}),
|
||||
},
|
||||
// '38;2' qualifies an RGB foreground color
|
||||
"\x1b[38;2;255;0;255mfoo\x1b[0m",
|
||||
|
|
@ -115,7 +115,7 @@ func TestMerge(t *testing.T) {
|
|||
TextStyle{
|
||||
fg: &rgbPink,
|
||||
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
|
||||
"\x1b[38;2;255;0;255;48;2;255;255;0mfoo\x1b[0m",
|
||||
|
|
@ -130,7 +130,7 @@ func TestMerge(t *testing.T) {
|
|||
bold: 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",
|
||||
},
|
||||
|
|
@ -140,7 +140,7 @@ func TestMerge(t *testing.T) {
|
|||
TextStyle{
|
||||
fg: &rgbYellow,
|
||||
bg: &Color{basic: &bgRed},
|
||||
style: color.NewRGBStyle(
|
||||
Style: color.NewRGBStyle(
|
||||
rgbYellowLib,
|
||||
fgRed.RGB(), // We need to use FG here, https://github.com/gookit/color/issues/39
|
||||
).SetOpts(color.Opts{}),
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ type TextStyle struct {
|
|||
bg *Color
|
||||
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 {
|
||||
|
|
@ -40,16 +42,16 @@ type Sprinter interface {
|
|||
|
||||
func New() TextStyle {
|
||||
s := TextStyle{}
|
||||
s.style = s.deriveStyle()
|
||||
s.Style = s.deriveStyle()
|
||||
return s
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
|
|
@ -57,31 +59,31 @@ func (b TextStyle) Sprintf(format string, a ...interface{}) string {
|
|||
// TextStyle receiver without actually modifying the original.
|
||||
func (b TextStyle) SetBold() TextStyle {
|
||||
b.decoration.SetBold()
|
||||
b.style = b.deriveStyle()
|
||||
b.Style = b.deriveStyle()
|
||||
return b
|
||||
}
|
||||
|
||||
func (b TextStyle) SetUnderline() TextStyle {
|
||||
b.decoration.SetUnderline()
|
||||
b.style = b.deriveStyle()
|
||||
b.Style = b.deriveStyle()
|
||||
return b
|
||||
}
|
||||
|
||||
func (b TextStyle) SetReverse() TextStyle {
|
||||
b.decoration.SetReverse()
|
||||
b.style = b.deriveStyle()
|
||||
b.Style = b.deriveStyle()
|
||||
return b
|
||||
}
|
||||
|
||||
func (b TextStyle) SetBg(color Color) TextStyle {
|
||||
b.bg = &color
|
||||
b.style = b.deriveStyle()
|
||||
b.Style = b.deriveStyle()
|
||||
return b
|
||||
}
|
||||
|
||||
func (b TextStyle) SetFg(color Color) TextStyle {
|
||||
b.fg = &color
|
||||
b.style = b.deriveStyle()
|
||||
b.Style = b.deriveStyle()
|
||||
return b
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +98,7 @@ func (b TextStyle) MergeStyle(other TextStyle) TextStyle {
|
|||
b.bg = other.bg
|
||||
}
|
||||
|
||||
b.style = b.deriveStyle()
|
||||
b.Style = b.deriveStyle()
|
||||
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
|
|
@ -20,18 +21,22 @@ func (gui *Gui) newCmdTask(view *gocui.View, cmd *exec.Cmd, prefix string) error
|
|||
|
||||
manager := gui.getManager(view)
|
||||
|
||||
r, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Stderr = cmd.Stdout
|
||||
start := func() (*exec.Cmd, io.Reader) {
|
||||
r, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
gui.Log.Warn(err)
|
||||
}
|
||||
cmd.Stderr = cmd.Stdout
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
if err := cmd.Start(); err != nil {
|
||||
gui.Log.Warn(err)
|
||||
}
|
||||
|
||||
return cmd, r
|
||||
}
|
||||
|
||||
if err := manager.NewTask(manager.NewCmdTask(r, cmd, prefix, height+oy+10, nil), cmdStr); err != nil {
|
||||
return err
|
||||
if err := manager.NewTask(manager.NewCmdTask(start, prefix, height+oy+10, nil), cmdStr); err != nil {
|
||||
gui.Log.Warn(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -90,7 +95,6 @@ func (gui *Gui) getManager(view *gocui.View) *tasks.ViewBufferManager {
|
|||
view.Reset()
|
||||
},
|
||||
func() {
|
||||
// gui.g.Draw(view) // doing this causes an issue when there's a popup panel in front of the main view.
|
||||
gui.render()
|
||||
},
|
||||
func() {
|
||||
|
|
|
|||
|
|
@ -308,6 +308,11 @@ func (gui *Gui) renderDisplayStrings(v *gocui.View, displayStrings [][]string) {
|
|||
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 {
|
||||
keybindingConfig := gui.Config.GetUserConfig().Keybinding
|
||||
|
||||
|
|
@ -318,6 +323,7 @@ func (gui *Gui) globalOptionsMap() map[string]string {
|
|||
gui.getKeyDisplay(keybindingConfig.Universal.Quit): gui.Tr.LcQuit,
|
||||
gui.getKeyDisplay(keybindingConfig.Universal.OptionMenu): gui.Tr.LcMenu,
|
||||
fmt.Sprintf("%s-%s", gui.getKeyDisplay(keybindingConfig.Universal.JumpToBlock[0]), gui.getKeyDisplay(keybindingConfig.Universal.JumpToBlock[len(keybindingConfig.Universal.JumpToBlock)-1])): gui.Tr.LcJump,
|
||||
fmt.Sprintf("%s/%s", gui.getKeyDisplay(keybindingConfig.Universal.ScrollLeft), gui.getKeyDisplay(keybindingConfig.Universal.ScrollRight)): gui.Tr.LcScrollLeftRight,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -271,6 +271,9 @@ type TranslationSet struct {
|
|||
LcStashOptions string
|
||||
NotARepository string
|
||||
LcJump string
|
||||
LcScrollLeftRight string
|
||||
LcScrollLeft string
|
||||
LcScrollRight string
|
||||
DiscardPatch string
|
||||
DiscardPatchConfirm string
|
||||
CantPatchWhileRebasingError string
|
||||
|
|
@ -434,6 +437,7 @@ type TranslationSet struct {
|
|||
SelectConfigFile string
|
||||
NoConfigFileFoundErr string
|
||||
LcLoadingFileSuggestions string
|
||||
LcLoadingCommits string
|
||||
MustSpecifyOriginError string
|
||||
GitOutput string
|
||||
GitCommandFailed string
|
||||
|
|
@ -441,6 +445,11 @@ type TranslationSet struct {
|
|||
AbortTitle string
|
||||
AbortPrompt string
|
||||
SelectRemoteRepository string
|
||||
LcOpenLogMenu string
|
||||
LogMenuTitle string
|
||||
ToggleShowGitGraphAll string
|
||||
ShowGitGraph string
|
||||
SortCommits string
|
||||
Spans Spans
|
||||
}
|
||||
|
||||
|
|
@ -805,6 +814,9 @@ func englishTranslationSet() TranslationSet {
|
|||
LcStashOptions: "Stash options",
|
||||
NotARepository: "Error: must be run inside a git repository",
|
||||
LcJump: "jump to panel",
|
||||
LcScrollLeftRight: "scroll left/right",
|
||||
LcScrollLeft: "scroll left",
|
||||
LcScrollRight: "scroll right",
|
||||
DiscardPatch: "Discard Patch",
|
||||
DiscardPatchConfirm: "You can only build a patch from one commit/stash-entry at a time. Discard current patch?",
|
||||
CantPatchWhileRebasingError: "You cannot build a patch or run patch commands while in a merging or rebasing state",
|
||||
|
|
@ -969,12 +981,18 @@ func englishTranslationSet() TranslationSet {
|
|||
SelectConfigFile: "Select config file",
|
||||
NoConfigFileFoundErr: "No config file found",
|
||||
LcLoadingFileSuggestions: "loading file suggestions",
|
||||
LcLoadingCommits: "loading commits",
|
||||
MustSpecifyOriginError: "Must specify a remote if specifying a branch",
|
||||
GitOutput: "Git output:",
|
||||
GitCommandFailed: "Git command failed. Check command log for details (open with %s)",
|
||||
OpenPr: "Open PR #",
|
||||
AbortTitle: "Abort %s",
|
||||
AbortPrompt: "Are you sure you want to abort the current %s?",
|
||||
LcOpenLogMenu: "open log menu",
|
||||
LogMenuTitle: "Commit Log Options",
|
||||
ToggleShowGitGraphAll: "toggle show whole git graph (pass the `--all` flag to `git log`)",
|
||||
ShowGitGraph: "show git graph",
|
||||
SortCommits: "commit sort order",
|
||||
Spans: Spans{
|
||||
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
||||
CheckoutCommit: "Checkout commit",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const THROTTLE_TIME = time.Millisecond * 30
|
||||
|
||||
// we use this to check if the system is under stress right now. Hopefully this makes sense on other machines
|
||||
const COMMAND_START_THRESHOLD = time.Millisecond * 10
|
||||
|
||||
type Task struct {
|
||||
stop chan struct{}
|
||||
stopped bool
|
||||
|
|
@ -38,6 +43,12 @@ type ViewBufferManager struct {
|
|||
beforeStart func()
|
||||
refreshView 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 {
|
||||
|
|
@ -69,18 +80,35 @@ 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 {
|
||||
if m.throttle {
|
||||
m.Log.Info("throttling task")
|
||||
time.Sleep(THROTTLE_TIME)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
cmd, r := start()
|
||||
timeToStart := time.Since(startTime)
|
||||
|
||||
go utils.Safe(func() {
|
||||
<-stop
|
||||
// we use the time it took to start the program as a way of checking if things
|
||||
// are running slow at the moment. This is admittedly a crude estimate, but
|
||||
// the point is that we only want to throttle when things are running slow
|
||||
// and the user is flicking through a bunch of items.
|
||||
m.throttle = time.Since(startTime) < THROTTLE_TIME && timeToStart > COMMAND_START_THRESHOLD
|
||||
if err := oscommands.Kill(cmd); err != nil {
|
||||
if !strings.Contains(err.Error(), "process already finished") {
|
||||
m.Log.Errorf("error when running cmd task: %v", err)
|
||||
}
|
||||
}
|
||||
if onDone != nil {
|
||||
onDone()
|
||||
}
|
||||
})
|
||||
|
||||
loadingMutex := sync.Mutex{}
|
||||
|
|
|
|||
|
|
@ -6,21 +6,24 @@ import (
|
|||
)
|
||||
|
||||
var decoloriseCache = make(map[string]string)
|
||||
var decoloriseMutex sync.Mutex
|
||||
var decoloriseMutex sync.RWMutex
|
||||
|
||||
// Decolorise strips a string of color
|
||||
func Decolorise(str string) string {
|
||||
decoloriseMutex.Lock()
|
||||
defer decoloriseMutex.Unlock()
|
||||
decoloriseMutex.RLock()
|
||||
val := decoloriseCache[str]
|
||||
decoloriseMutex.RUnlock()
|
||||
|
||||
if decoloriseCache[str] != "" {
|
||||
return decoloriseCache[str]
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`\x1B\[([0-9]{1,3}(;[0-9]{1,3})*)?[mGK]`)
|
||||
ret := re.ReplaceAllString(str, "")
|
||||
|
||||
decoloriseMutex.Lock()
|
||||
decoloriseCache[str] = ret
|
||||
decoloriseMutex.Unlock()
|
||||
|
||||
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
|
||||
|
||||
ViewsMutex sync.Mutex
|
||||
|
||||
drawMutex sync.Mutex
|
||||
}
|
||||
|
||||
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.
|
||||
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
|
||||
// g.clear(g.FgColor, g.BgColor)
|
||||
|
|
@ -966,18 +962,6 @@ func (g *Gui) flush() error {
|
|||
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.
|
||||
func (g *Gui) draw(v *View) error {
|
||||
if g.suspended {
|
||||
|
|
|
|||
69
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
69
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
|
|
@ -218,7 +218,7 @@ func (v *View) SelectSearchResult(index int) error {
|
|||
}
|
||||
|
||||
y := v.searcher.searchPositions[index].y
|
||||
v.FocusPoint(0, y)
|
||||
v.FocusPoint(v.ox, y)
|
||||
if v.searcher.onSelectItem != nil {
|
||||
return v.searcher.onSelectItem(y, index, itemCount)
|
||||
}
|
||||
|
|
@ -227,10 +227,9 @@ func (v *View) SelectSearchResult(index int) error {
|
|||
|
||||
func (v *View) Search(str string) error {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.searcher.search(str)
|
||||
v.updateSearchPositions()
|
||||
|
||||
if len(v.searcher.searchPositions) > 0 {
|
||||
// get the first result past the current cursor
|
||||
currentIndex := 0
|
||||
|
|
@ -243,8 +242,10 @@ func (v *View) Search(str string) error {
|
|||
}
|
||||
}
|
||||
v.searcher.currentSearchIndex = currentIndex
|
||||
v.writeMutex.Unlock()
|
||||
return v.SelectSearchResult(currentIndex)
|
||||
} else {
|
||||
v.writeMutex.Unlock()
|
||||
return v.searcher.onSelectItem(-1, -1, 0)
|
||||
}
|
||||
}
|
||||
|
|
@ -475,9 +476,33 @@ func (v *View) SetOrigin(x, y int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *View) SetOriginX(x int) error {
|
||||
if x < 0 {
|
||||
return ErrInvalidPoint
|
||||
}
|
||||
v.ox = x
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) SetOriginY(y int) error {
|
||||
if y < 0 {
|
||||
return ErrInvalidPoint
|
||||
}
|
||||
v.oy = y
|
||||
return nil
|
||||
}
|
||||
|
||||
// Origin returns the origin position of the view.
|
||||
func (v *View) Origin() (x, y int) {
|
||||
return v.ox, v.oy
|
||||
return v.OriginX(), v.OriginY()
|
||||
}
|
||||
|
||||
func (v *View) OriginX() int {
|
||||
return v.ox
|
||||
}
|
||||
|
||||
func (v *View) OriginY() int {
|
||||
return v.oy
|
||||
}
|
||||
|
||||
// SetWritePos sets the write position of the view's internal buffer.
|
||||
|
|
@ -879,11 +904,18 @@ func (v *View) draw() error {
|
|||
if v.Autoscroll && 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
|
||||
for i, vline := range v.viewLines {
|
||||
if i < v.oy {
|
||||
continue
|
||||
}
|
||||
for _, vline := range v.viewLines[start:] {
|
||||
if y >= maxY {
|
||||
break
|
||||
}
|
||||
|
|
@ -1112,14 +1144,6 @@ func (v *View) SetHighlight(y int, on bool) error {
|
|||
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 {
|
||||
if columns == 0 {
|
||||
return [][]cell{line}
|
||||
|
|
@ -1227,3 +1251,16 @@ func (v *View) ClearTextArea() {
|
|||
_ = v.SetOrigin(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
|
||||
}
|
||||
|
||||
func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) {
|
||||
mib, err := sysctlmib(name)
|
||||
func SysctlKinfoProc(name string, args ...int) (*KinfoProc, error) {
|
||||
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 {
|
||||
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_LOCALTLK = 0x305
|
||||
ARPHRD_LOOPBACK = 0x304
|
||||
ARPHRD_MCTP = 0x122
|
||||
ARPHRD_METRICOM = 0x17
|
||||
ARPHRD_NETLINK = 0x338
|
||||
ARPHRD_NETROM = 0x0
|
||||
|
|
@ -472,6 +473,7 @@ const (
|
|||
DM_DEV_WAIT = 0xc138fd08
|
||||
DM_DIR = "mapper"
|
||||
DM_GET_TARGET_VERSION = 0xc138fd11
|
||||
DM_IMA_MEASUREMENT_FLAG = 0x80000
|
||||
DM_INACTIVE_PRESENT_FLAG = 0x40
|
||||
DM_INTERNAL_SUSPEND_FLAG = 0x40000
|
||||
DM_IOCTL = 0xfd
|
||||
|
|
@ -716,6 +718,7 @@ const (
|
|||
ETH_P_LOOPBACK = 0x9000
|
||||
ETH_P_MACSEC = 0x88e5
|
||||
ETH_P_MAP = 0xf9
|
||||
ETH_P_MCTP = 0xfa
|
||||
ETH_P_MOBITEX = 0x15
|
||||
ETH_P_MPLS_MC = 0x8848
|
||||
ETH_P_MPLS_UC = 0x8847
|
||||
|
|
@ -751,6 +754,21 @@ const (
|
|||
ETH_P_WCCP = 0x883e
|
||||
ETH_P_X25 = 0x805
|
||||
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
|
||||
EXT2_SUPER_MAGIC = 0xef53
|
||||
EXT3_SUPER_MAGIC = 0xef53
|
||||
|
|
@ -789,9 +807,11 @@ const (
|
|||
FAN_DELETE_SELF = 0x400
|
||||
FAN_DENY = 0x2
|
||||
FAN_ENABLE_AUDIT = 0x40
|
||||
FAN_EPIDFD = -0x2
|
||||
FAN_EVENT_INFO_TYPE_DFID = 0x3
|
||||
FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2
|
||||
FAN_EVENT_INFO_TYPE_FID = 0x1
|
||||
FAN_EVENT_INFO_TYPE_PIDFD = 0x4
|
||||
FAN_EVENT_METADATA_LEN = 0x18
|
||||
FAN_EVENT_ON_CHILD = 0x8000000
|
||||
FAN_MARK_ADD = 0x1
|
||||
|
|
@ -811,6 +831,7 @@ const (
|
|||
FAN_MOVE_SELF = 0x800
|
||||
FAN_NOFD = -0x1
|
||||
FAN_NONBLOCK = 0x2
|
||||
FAN_NOPIDFD = -0x1
|
||||
FAN_ONDIR = 0x40000000
|
||||
FAN_OPEN = 0x20
|
||||
FAN_OPEN_EXEC = 0x1000
|
||||
|
|
@ -821,6 +842,7 @@ const (
|
|||
FAN_REPORT_DIR_FID = 0x400
|
||||
FAN_REPORT_FID = 0x200
|
||||
FAN_REPORT_NAME = 0x800
|
||||
FAN_REPORT_PIDFD = 0x80
|
||||
FAN_REPORT_TID = 0x100
|
||||
FAN_UNLIMITED_MARKS = 0x20
|
||||
FAN_UNLIMITED_QUEUE = 0x10
|
||||
|
|
@ -1997,6 +2019,7 @@ const (
|
|||
PR_SPEC_ENABLE = 0x2
|
||||
PR_SPEC_FORCE_DISABLE = 0x8
|
||||
PR_SPEC_INDIRECT_BRANCH = 0x1
|
||||
PR_SPEC_L1D_FLUSH = 0x2
|
||||
PR_SPEC_NOT_AFFECTED = 0x0
|
||||
PR_SPEC_PRCTL = 0x1
|
||||
PR_SPEC_STORE_BYPASS = 0x0
|
||||
|
|
@ -2432,12 +2455,15 @@ const (
|
|||
SMART_WRITE_THRESHOLDS = 0xd7
|
||||
SMB_SUPER_MAGIC = 0x517b
|
||||
SOCKFS_MAGIC = 0x534f434b
|
||||
SOCK_BUF_LOCK_MASK = 0x3
|
||||
SOCK_DCCP = 0x6
|
||||
SOCK_IOC_TYPE = 0x89
|
||||
SOCK_PACKET = 0xa
|
||||
SOCK_RAW = 0x3
|
||||
SOCK_RCVBUF_LOCK = 0x2
|
||||
SOCK_RDM = 0x4
|
||||
SOCK_SEQPACKET = 0x5
|
||||
SOCK_SNDBUF_LOCK = 0x1
|
||||
SOL_AAL = 0x109
|
||||
SOL_ALG = 0x117
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x20
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x20
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x20
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x20
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x6
|
||||
SO_BSDCOMPAT = 0xe
|
||||
SO_BUF_LOCK = 0x48
|
||||
SO_BUSY_POLL = 0x2e
|
||||
SO_BUSY_POLL_BUDGET = 0x46
|
||||
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_BROADCAST = 0x20
|
||||
SO_BSDCOMPAT = 0x400
|
||||
SO_BUF_LOCK = 0x51
|
||||
SO_BUSY_POLL = 0x30
|
||||
SO_BUSY_POLL_BUDGET = 0x49
|
||||
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_RESTRICT_SELF = 446
|
||||
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_RESTRICT_SELF = 446
|
||||
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
|
||||
|
||||
const (
|
||||
SYS_SYSCALL_MASK = 0
|
||||
SYS_RESTART_SYSCALL = 0
|
||||
SYS_EXIT = 1
|
||||
SYS_FORK = 2
|
||||
|
|
@ -407,4 +408,5 @@ const (
|
|||
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||
SYS_LANDLOCK_ADD_RULE = 445
|
||||
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_RESTRICT_SELF = 446
|
||||
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_ADD_RULE = 4445
|
||||
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_ADD_RULE = 5445
|
||||
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_ADD_RULE = 5445
|
||||
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_ADD_RULE = 4445
|
||||
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_ADD_RULE = 445
|
||||
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_ADD_RULE = 445
|
||||
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_ADD_RULE = 445
|
||||
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_ADD_RULE = 445
|
||||
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_ADD_RULE = 445
|
||||
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_ADD_RULE = 445
|
||||
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_SEG6_LOCAL = 0x7
|
||||
LWTUNNEL_ENCAP_RPL = 0x8
|
||||
LWTUNNEL_ENCAP_MAX = 0x8
|
||||
LWTUNNEL_ENCAP_IOAM6 = 0x9
|
||||
LWTUNNEL_ENCAP_MAX = 0x9
|
||||
|
||||
MPLS_IPTUNNEL_UNSPEC = 0x0
|
||||
MPLS_IPTUNNEL_DST = 0x1
|
||||
|
|
@ -3617,7 +3618,9 @@ const (
|
|||
ETHTOOL_A_COALESCE_TX_USECS_HIGH = 0x15
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH = 0x16
|
||||
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_HEADER = 0x1
|
||||
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/internal/frame
|
||||
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.20211102104458-40df0be5a474
|
||||
## explicit
|
||||
github.com/jesseduffield/gocui
|
||||
# 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/internal/socks
|
||||
golang.org/x/net/proxy
|
||||
# golang.org/x/sys v0.0.0-20211031064116-611d5d643895
|
||||
# golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c
|
||||
## explicit
|
||||
golang.org/x/sys/cpu
|
||||
golang.org/x/sys/internal/unsafeheader
|
||||
|
|
|
|||
Loading…
Reference in a new issue