mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-11 12:25:47 +02:00
render commit graph
This commit is contained in:
parent
2fc1498517
commit
802cfb1a04
53 changed files with 543 additions and 284 deletions
|
@ -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)
|
||||
|
|
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.20211102081536-e4eee64f4d13
|
||||
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.20211102081536-e4eee64f4d13 h1:JB1nYX2l3s9aBtw4Ymc7KXp/Hk3IukO4u+APok6WWjo=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20211102081536-e4eee64f4d13/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
|
||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/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=
|
||||
|
|
|
@ -406,7 +406,7 @@ func (c *CommitListBuilder) getLogCmd(opts GetCommitsOptions) *exec.Cmd {
|
|||
|
||||
return c.OSCommand.ExecutableFromString(
|
||||
fmt.Sprintf(
|
||||
"git log %s --oneline %s %s --abbrev=%d %s",
|
||||
"git log --topo-order %s --oneline %s %s --abbrev=%d %s",
|
||||
c.OSCommand.Quote(opts.RefName),
|
||||
prettyFormat,
|
||||
limitFlag,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -395,7 +395,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: ""},
|
||||
|
|
|
@ -14,6 +14,10 @@ type ListContext struct {
|
|||
// the boolean here tells us whether the item is nil. This is needed because you can't work it out on the calling end once the pointer is wrapped in an interface (unless you want to use reflection)
|
||||
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
|
||||
|
||||
|
@ -60,10 +64,17 @@ type ListItem interface {
|
|||
func (self *ListContext) FocusLine() {
|
||||
view, err := self.Gui.g.View(self.ViewName)
|
||||
if err != nil {
|
||||
// ignoring error for now
|
||||
return
|
||||
}
|
||||
|
||||
// we need a way of knowing whether we've rendered to the view yet.
|
||||
view.FocusPoint(0, self.GetPanelState().GetSelectedLineIdx())
|
||||
if self.RenderSelection {
|
||||
_, originY := view.Origin()
|
||||
displayStrings := self.GetDisplayStrings(originY, view.InnerHeight())
|
||||
self.Gui.renderDisplayStringsAtPos(view, originY, displayStrings)
|
||||
}
|
||||
view.Footer = formatListFooter(self.GetPanelState().GetSelectedLineIdx(), self.GetItemsLength())
|
||||
}
|
||||
|
||||
|
|
|
@ -157,18 +157,29 @@ 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,
|
||||
)
|
||||
},
|
||||
SelectedItem: func() (ListItem, bool) {
|
||||
item := gui.getSelectedLocalCommit()
|
||||
return item, item != nil
|
||||
},
|
||||
RenderSelection: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,18 +226,29 @@ 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),
|
||||
)
|
||||
},
|
||||
SelectedItem: func() (ListItem, bool) {
|
||||
item := gui.getSelectedSubCommit()
|
||||
return item, item != nil
|
||||
},
|
||||
RenderSelection: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,120 +2,152 @@ 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
|
||||
} else {
|
||||
displayFunc = getDisplayStringsForCommit
|
||||
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,
|
||||
) [][]string {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if len(commits) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := range commits {
|
||||
diffed := commits[i].Sha == diffName
|
||||
lines[i] = displayFunc(commits[i], cherryPickedCommitShaMap, diffed, parseEmoji)
|
||||
// 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
|
||||
}
|
||||
|
||||
end := startIdx + length
|
||||
if end > len(commits)-1 {
|
||||
end = len(commits) - 1
|
||||
}
|
||||
|
||||
filteredPipeSets := pipeSets[startIdx : end+1]
|
||||
filteredCommits := commits[startIdx : end+1]
|
||||
graphLines := graph.RenderAux(filteredPipeSets, filteredCommits, selectedCommitSha)
|
||||
|
||||
lines := make([][]string, 0, len(graphLines))
|
||||
for i, commit := range filteredCommits {
|
||||
lines = append(lines, displayCommit(commit, cherryPickedCommitShaMap, diffName, parseEmoji, graphLines[i], fullDescription))
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
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,11 +26,11 @@ 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
|
||||
|
@ -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"
|
||||
|
@ -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,7 +264,7 @@ 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},
|
||||
},
|
||||
|
@ -271,7 +274,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
},
|
||||
{
|
||||
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},
|
||||
},
|
||||
|
@ -281,7 +284,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
},
|
||||
{
|
||||
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,7 +342,7 @@ 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},
|
||||
|
@ -353,7 +356,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
},
|
||||
{
|
||||
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,7 +401,7 @@ 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},
|
||||
},
|
||||
|
@ -410,7 +413,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
},
|
||||
{
|
||||
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},
|
||||
},
|
||||
|
@ -422,7 +425,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "commit whose previous commit is selected and is a merge commit, with continuing pipe inbetween",
|
||||
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},
|
||||
|
@ -435,7 +438,7 @@ func TestRenderPipeSet(t *testing.T) {
|
|||
},
|
||||
{
|
||||
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
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const THROTTLE_TIME = time.Millisecond * 30
|
||||
|
||||
type Task struct {
|
||||
stop chan struct{}
|
||||
stopped bool
|
||||
|
@ -38,6 +40,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 +77,31 @@ func (m *ViewBufferManager) ReadLines(n int) {
|
|||
})
|
||||
}
|
||||
|
||||
func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string, linesToRead int, onDone func()) func(chan struct{}) error {
|
||||
func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), prefix string, linesToRead int, onDone func()) func(chan struct{}) error {
|
||||
return func(stop chan struct{}) error {
|
||||
if m.throttle {
|
||||
m.Log.Info("throttling task")
|
||||
time.Sleep(THROTTLE_TIME)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
cmd, r := start()
|
||||
|
||||
go utils.Safe(func() {
|
||||
<-stop
|
||||
m.throttle = time.Since(startTime) < THROTTLE_TIME
|
||||
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 {
|
||||
|
|
36
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
36
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
|
@ -879,11 +879,18 @@ func (v *View) draw() error {
|
|||
if v.Autoscroll && visibleViewLinesHeight > maxY {
|
||||
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 +1119,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 +1226,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.20211102081536-e4eee64f4d13
|
||||
## 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…
Add table
Add a link
Reference in a new issue