Compare commits

..
Author SHA1 Message Date
Jesse Duffield 4a07e03701 Local-ise remote branches when checking out by name
The idea here is that in the git CLI you will often want to checkout a
remote branch like origin/blah by doing `git checkout blah`. That will
automatically create a local branch named blah that tracks origin/blah.

Previously in the suggestions view when checking out a branch by name,
we would only show local branches and remote branches like origin/blah
but wouldn't show blah as an option (assuming no local branch existed
with that name). This meant users would checkout origin/blah and git
would check out that branch as a detached head which is rarely what you
actually want.

Now we give them both options. The alternative approach we could have
taken is to still show the branch as origin/blah but then ask if the
user wants to check out the branch as detached or as a local branch
tracking the remote branch. That approach is certainly more versatile,
but it's also something you can do already by going to the remote branch
directly via the remotes view. Admittedly, my approach involves less
work.
2024-03-09 13:53:14 +11:00
35 changed files with 209 additions and 902 deletions
+3 -14
View File
@@ -1,24 +1,15 @@
# see https://github.com/JamesIves/github-sponsors-readme-action
name: Generate Sponsors README
on:
push:
branches:
- master
pull_request: # Add this if you want to run checks on PRs as well
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
with:
ref: master # This ensures the checkout step fetches the master branch
- name: Switch to master branch
run: |
git fetch origin master:refs/remotes/origin/master
git checkout master
- name: Generate Sponsors 💖
uses: JamesIves/github-sponsors-readme-action@v1.2.2
@@ -33,7 +24,5 @@ jobs:
git config --global user.email "actions@users.noreply.github.com"
git config --global user.name "README-bot"
git add README.md
git commit -m "Updated README.md [skip ci]" || exit 0
git push origin master # Explicitly push to master branch
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_API_TOKEN }}
git commit -m "Updated README.md" || exit 0
git push
-2
View File
@@ -92,8 +92,6 @@ git:
useConfig: false
commit:
signOff: false
autoWrapCommitMessage: true # automatic WYSIWYG wrapping of the commit message as you type
autoWrapWidth: 72 # if autoWrapCommitMessage is true, the width to wrap to
merging:
# only applicable to unix users
manualCommit: false
+4 -4
View File
@@ -9,14 +9,14 @@ require (
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/creack/pty v1.1.11
github.com/fsmiamoto/git-todo-parser v0.0.5
github.com/gdamore/tcell/v2 v2.7.4
github.com/gdamore/tcell/v2 v2.7.3
github.com/go-errors/errors v1.5.1
github.com/gookit/color v1.4.2
github.com/imdario/mergo v0.3.11
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
github.com/jesseduffield/gocui v0.3.1-0.20240309085756-86e0d5a312de
github.com/jesseduffield/gocui v0.3.1-0.20240303173746-f2b0f1f68dd8
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
@@ -74,8 +74,8 @@ require (
github.com/xanzy/ssh-agent v0.2.1 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
+6 -8
View File
@@ -89,8 +89,8 @@ github.com/fsmiamoto/git-todo-parser v0.0.5/go.mod h1:B+AgTbNE2BARvJqzXygThzqxLI
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
github.com/gdamore/tcell/v2 v2.7.3 h1:YLQlOj5F0hSlKy5TJvlych29+WTcJzbElnLYwx8gvdg=
github.com/gdamore/tcell/v2 v2.7.3/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
@@ -187,8 +187,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20240309085756-86e0d5a312de h1:2ww1SWgakihE8hFxZ7L3agVeGpA6qwW5vdnhFUXKMQo=
github.com/jesseduffield/gocui v0.3.1-0.20240309085756-86e0d5a312de/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
github.com/jesseduffield/gocui v0.3.1-0.20240303173746-f2b0f1f68dd8 h1:DGyAjpaAnxDuKO4MEoFjifhkUV7sU6znMR9eRfjjvn0=
github.com/jesseduffield/gocui v0.3.1-0.20240303173746-f2b0f1f68dd8/go.mod h1:lLLfxEGyIvvkzzpHdKkfgIVFmxqEejeACxKMVxSHLeM=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
@@ -470,15 +470,13 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+1 -1
View File
@@ -142,7 +142,7 @@ func (self *CommitCommands) GetCommitMessage(commitSha string) (string, error) {
ToArgv()
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
return strings.ReplaceAll(strings.TrimSpace(message), "\r\n", "\n"), err
return strings.TrimSpace(message), err
}
func (self *CommitCommands) GetCommitSubject(commitSha string) (string, error) {
+1 -7
View File
@@ -236,10 +236,6 @@ type PagingConfig struct {
type CommitConfig struct {
// If true, pass '--signoff' flag when committing
SignOff bool `yaml:"signOff"`
// Automatic WYSIWYG wrapping of the commit message as you type
AutoWrapCommitMessage bool `yaml:"autoWrapCommitMessage"`
// If autoWrapCommitMessage is true, the width to wrap to
AutoWrapWidth int `yaml:"autoWrapWidth"`
}
type MergingConfig struct {
@@ -662,9 +658,7 @@ func GetDefaultConfig() *UserConfig {
ExternalDiffCommand: "",
},
Commit: CommitConfig{
SignOff: false,
AutoWrapCommitMessage: true,
AutoWrapWidth: 72,
SignOff: false,
},
Merging: MergingConfig{
ManualCommit: false,
-4
View File
@@ -38,14 +38,10 @@ func (gui *Gui) resetHelpersAndControllers() {
getCommitDescription := func() string {
return strings.TrimSpace(gui.Views.CommitDescription.TextArea.GetContent())
}
getUnwrappedCommitDescription := func() string {
return strings.TrimSpace(gui.Views.CommitDescription.TextArea.GetUnwrappedContent())
}
commitsHelper := helpers.NewCommitsHelper(helperCommon,
getCommitSummary,
setCommitSummary,
getCommitDescription,
getUnwrappedCommitDescription,
setCommitDescription,
)
+1 -1
View File
@@ -433,7 +433,7 @@ func (self *BranchesController) forceCheckout() error {
func (self *BranchesController) checkoutByName() error {
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.BranchName + ":",
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRefsSuggestionsFunc(),
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetCheckoutBranchesSuggestionsFunc(),
HandleConfirm: func(response string) error {
self.c.LogAction("Checkout branch")
return self.c.Helpers().Refs.CheckoutRef(response, types.CheckoutRefOptions{
@@ -3,7 +3,6 @@ package controllers
import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@@ -101,7 +100,7 @@ func (self *CommitMessageController) handleCommitIndexChange(value int) error {
self.c.Helpers().Commits.SetMessageAndDescriptionInView(self.context().GetHistoryMessage())
return nil
} else if currentIndex == context.NoCommitIndex {
self.context().SetHistoryMessage(self.c.Helpers().Commits.JoinCommitMessageAndUnwrappedDescription())
self.context().SetHistoryMessage(self.c.Helpers().Commits.JoinCommitMessageAndDescription())
}
validCommit, err := self.setCommitMessageAtIndex(newIndex)
@@ -120,9 +119,6 @@ func (self *CommitMessageController) setCommitMessageAtIndex(index int) (bool, e
}
return false, self.c.ErrorMsg(self.c.Tr.CommitWithoutMessageErr)
}
if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage {
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth)
}
self.c.Helpers().Commits.UpdateCommitPanelView(commitMessage)
return true, nil
}
+13 -42
View File
@@ -5,7 +5,6 @@ import (
"strings"
"time"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
@@ -17,11 +16,10 @@ type ICommitsHelper interface {
type CommitsHelper struct {
c *HelperCommon
getCommitSummary func() string
setCommitSummary func(string)
getCommitDescription func() string
getUnwrappedCommitDescription func() string
setCommitDescription func(string)
getCommitSummary func() string
setCommitSummary func(string)
getCommitDescription func() string
setCommitDescription func(string)
}
var _ ICommitsHelper = &CommitsHelper{}
@@ -31,16 +29,14 @@ func NewCommitsHelper(
getCommitSummary func() string,
setCommitSummary func(string),
getCommitDescription func() string,
getUnwrappedCommitDescription func() string,
setCommitDescription func(string),
) *CommitsHelper {
return &CommitsHelper{
c: c,
getCommitSummary: getCommitSummary,
setCommitSummary: setCommitSummary,
getCommitDescription: getCommitDescription,
getUnwrappedCommitDescription: getUnwrappedCommitDescription,
setCommitDescription: setCommitDescription,
c: c,
getCommitSummary: getCommitSummary,
setCommitSummary: setCommitSummary,
getCommitDescription: getCommitDescription,
setCommitDescription: setCommitDescription,
}
}
@@ -57,36 +53,11 @@ func (self *CommitsHelper) SetMessageAndDescriptionInView(message string) {
self.c.Contexts().CommitMessage.RenderCommitLength()
}
func (self *CommitsHelper) JoinCommitMessageAndUnwrappedDescription() string {
if len(self.getUnwrappedCommitDescription()) == 0 {
func (self *CommitsHelper) JoinCommitMessageAndDescription() string {
if len(self.getCommitDescription()) == 0 {
return self.getCommitSummary()
}
return self.getCommitSummary() + "\n" + self.getUnwrappedCommitDescription()
}
func TryRemoveHardLineBreaks(message string, autoWrapWidth int) string {
messageRunes := []rune(message)
lastHardLineStart := 0
for i, r := range messageRunes {
if r == '\n' {
// Try to make this a soft linebreak by turning it into a space, and
// checking whether it still wraps to the same result then.
messageRunes[i] = ' '
_, cursorMapping := gocui.AutoWrapContent(messageRunes[lastHardLineStart:], autoWrapWidth)
// Look at the cursorMapping to check whether auto-wrapping inserted
// a line break. If it did, there will be a cursorMapping entry with
// Orig pointing to the position after the inserted line break.
if len(cursorMapping) == 0 || cursorMapping[0].Orig != i-lastHardLineStart+1 {
// It didn't, so change it back to a newline
messageRunes[i] = '\n'
}
lastHardLineStart = i + 1
}
}
return string(messageRunes)
return self.getCommitSummary() + "\n" + self.getCommitDescription()
}
func (self *CommitsHelper) SwitchToEditor() error {
@@ -183,7 +154,7 @@ func (self *CommitsHelper) HandleCommitConfirm() error {
func (self *CommitsHelper) CloseCommitMessagePanel() error {
if self.c.Contexts().CommitMessage.GetPreserveMessage() {
message := self.JoinCommitMessageAndUnwrappedDescription()
message := self.JoinCommitMessageAndDescription()
self.c.Contexts().CommitMessage.SetPreservedMessage(message)
} else {
@@ -1,41 +0,0 @@
package helpers
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestTryRemoveHardLineBreaks(t *testing.T) {
scenarios := []struct {
name string
message string
autoWrapWidth int
expectedResult string
}{
{
name: "empty",
message: "",
autoWrapWidth: 7,
expectedResult: "",
},
{
name: "all line breaks are needed",
message: "abc\ndef\n\nxyz",
autoWrapWidth: 7,
expectedResult: "abc\ndef\n\nxyz",
},
{
name: "some can be unwrapped",
message: "123\nabc def\nghi jkl\nmno\n456\n",
autoWrapWidth: 7,
expectedResult: "123\nabc def ghi jkl mno\n456\n",
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
actualResult := TryRemoveHardLineBreaks(s.message, s.autoWrapWidth)
assert.Equal(t, s.expectedResult, actualResult)
})
}
}
@@ -3,6 +3,7 @@ package helpers
import (
"fmt"
"os"
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
@@ -25,6 +26,8 @@ import (
// finding suggestions in this file, so that it's easy to see if a function already
// exists for fetching a particular model.
var specialRefNames = []string{"HEAD", "FETCH_HEAD", "MERGE_HEAD", "ORIG_HEAD"}
type ISuggestionsHelper interface {
GetRemoteSuggestionsFunc() func(string) []*types.Suggestion
GetBranchNameSuggestionsFunc() func(string) []*types.Suggestion
@@ -168,9 +171,29 @@ func (self *SuggestionsHelper) GetRefsSuggestionsFunc() func(string) []*types.Su
remoteBranchNames := self.getRemoteBranchNames("/")
localBranchNames := self.getBranchNames()
tagNames := self.getTagNames()
additionalRefNames := []string{"HEAD", "FETCH_HEAD", "MERGE_HEAD", "ORIG_HEAD"}
refNames := append(append(append(remoteBranchNames, localBranchNames...), tagNames...), additionalRefNames...)
refNames := append(append(append(remoteBranchNames, localBranchNames...), tagNames...), specialRefNames...)
return FuzzySearchFunc(refNames)
}
func (self *SuggestionsHelper) GetCheckoutBranchesSuggestionsFunc() func(string) []*types.Suggestion {
remoteBranchNames := self.getRemoteBranchNames("/")
// We include remote branches with the remote stripped off in the list of suggestions
// so that you can check out the branch as a local branch tracking the remote branch, just
// like you can do in the git CLI. I.e. if you checkout 'origin/blah' it will be
// checked out as as a detached head, but if you checkout 'blah' it will be checked out
// as a local branch tracking 'origin/blah'.
localisedRemoteBranchNames := lo.Map(remoteBranchNames, func(branchName string, _ int) string {
// strip the remote name from the branch name
return branchName[strings.Index(branchName, "/")+1:]
})
localBranchNames := self.getBranchNames()
tagNames := self.getTagNames()
refNames := append(append(append(append(remoteBranchNames, localBranchNames...), tagNames...), specialRefNames...), localisedRemoteBranchNames...)
refNames = lo.Uniq(refNames)
return FuzzySearchFunc(refNames)
}
+30 -93
View File
@@ -2,7 +2,6 @@ package controllers
import (
"fmt"
"strings"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/go-errors/errors"
@@ -116,6 +115,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
{
Key: opts.GetKey(editCommitKey),
Handler: self.withItems(self.edit),
// TODO: have disabled reason ensure that if we're not rebasing, we only select one commit
GetDisabledReason: self.require(
self.itemRangeSelected(self.midRebaseCommandEnabled),
),
@@ -354,9 +354,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
if err != nil {
return self.c.Error(err)
}
if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage {
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth)
}
return self.c.Helpers().Commits.OpenCommitMessagePanel(
&helpers.OpenCommitMessagePanelOpts{
CommitIndex: self.context().GetSelectedLineIdx(),
@@ -459,7 +457,15 @@ func (self *LocalCommitsController) edit(selectedCommits []*models.Commit) error
return self.updateTodos(todo.Edit, selectedCommits)
}
return self.startInteractiveRebaseWithEdit(selectedCommits)
// TODO: support range select here (start a rebase and set the selected commits
// to 'edit' in the todo file)
if len(selectedCommits) > 1 {
return self.c.ErrorMsg(self.c.Tr.RangeSelectNotSupported)
}
selectedCommit := selectedCommits[0]
return self.startInteractiveRebaseWithEdit(selectedCommit)
}
func (self *LocalCommitsController) quickStartInteractiveRebase() error {
@@ -468,11 +474,11 @@ func (self *LocalCommitsController) quickStartInteractiveRebase() error {
return self.c.Error(err)
}
return self.startInteractiveRebaseWithEdit([]*models.Commit{commitToEdit})
return self.startInteractiveRebaseWithEdit(commitToEdit)
}
func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
commitsToEdit []*models.Commit,
commitToEdit *models.Commit,
) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.EditCommit)
@@ -480,24 +486,10 @@ func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
commits := self.c.Model().Commits
selectedSha := commits[selectedIdx].Sha
rangeStartSha := commits[rangeStartIdx].Sha
err := self.c.Git().Rebase.EditRebase(commitsToEdit[len(commitsToEdit)-1].Sha)
err := self.c.Git().Rebase.EditRebase(commitToEdit.Sha)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
err,
types.RefreshOptions{Mode: types.BLOCK_UI, Then: func() {
todos := make([]*models.Commit, 0, len(commitsToEdit)-1)
for _, c := range commitsToEdit[:len(commitsToEdit)-1] {
// Merge commits can't be set to "edit", so just skip them
if !c.IsMerge() {
todos = append(todos, &models.Commit{Sha: c.Sha, Action: todo.Pick})
}
}
if len(todos) > 0 {
err := self.updateTodos(todo.Edit, todos)
if err != nil {
_ = self.c.Error(err)
}
}
// We need to select the same commit range again because after starting a rebase,
// new lines can be added for update-ref commands in the TODO file, due to
// stacked branches. So the selected commits may be in different positions in the list.
@@ -814,14 +806,11 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
HandleConfirm: func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit)
return self.c.WithWaitingStatusSync(self.c.Tr.CreatingFixupCommitStatus, func() error {
if err := self.c.Git().Commit.CreateFixupCommit(commit.Sha); err != nil {
return self.c.Error(err)
}
if err := self.c.Git().Commit.CreateFixupCommit(commit.Sha); err != nil {
return self.c.Error(err)
}
self.context().MoveSelectedLine(1)
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC})
})
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
})
},
})
@@ -850,89 +839,37 @@ func (self *LocalCommitsController) squashFixupCommits() error {
}
func (self *LocalCommitsController) squashAllFixupsAboveSelectedCommit(commit *models.Commit) error {
return self.squashFixupsImpl(commit, self.context().GetSelectedLineIdx())
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
err := self.c.Git().Rebase.SquashAllAboveFixupCommits(commit)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
})
}
func (self *LocalCommitsController) squashAllFixupsInCurrentBranch() error {
commit, rebaseStartIdx, err := self.findCommitForSquashFixupsInCurrentBranch()
commit, err := self.findCommitForSquashFixupsInCurrentBranch()
if err != nil {
return self.c.Error(err)
}
return self.squashFixupsImpl(commit, rebaseStartIdx)
}
func (self *LocalCommitsController) squashFixupsImpl(commit *models.Commit, rebaseStartIdx int) error {
selectionOffset := countSquashableCommitsAbove(self.c.Model().Commits, self.context().GetSelectedLineIdx(), rebaseStartIdx)
return self.c.WithWaitingStatusSync(self.c.Tr.SquashingStatus, func() error {
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
err := self.c.Git().Rebase.SquashAllAboveFixupCommits(commit)
self.context().MoveSelectedLine(-selectionOffset)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
err, types.RefreshOptions{Mode: types.SYNC})
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
})
}
func (self *LocalCommitsController) findCommitForSquashFixupsInCurrentBranch() (*models.Commit, int, error) {
func (self *LocalCommitsController) findCommitForSquashFixupsInCurrentBranch() (*models.Commit, error) {
commits := self.c.Model().Commits
_, index, ok := lo.FindIndexOf(commits, func(c *models.Commit) bool {
return c.IsMerge() || c.Status == models.StatusMerged
})
if !ok || index == 0 {
return nil, -1, errors.New(self.c.Tr.CannotSquashCommitsInCurrentBranch)
return nil, errors.New(self.c.Tr.CannotSquashCommitsInCurrentBranch)
}
return commits[index-1], index - 1, nil
}
// Anticipate how many commits above the selectedIdx are going to get squashed
// by the SquashAllAboveFixupCommits call, so that we can adjust the selection
// afterwards. Let's hope we're matching git's behavior correctly here.
func countSquashableCommitsAbove(commits []*models.Commit, selectedIdx int, rebaseStartIdx int) int {
result := 0
// For each commit _above_ the selection, ...
for i, commit := range commits[0:selectedIdx] {
// ... see if it is a fixup commit, and get the base subject it applies to
if baseSubject, isFixup := isFixupCommit(commit.Name); isFixup {
// Then, for each commit after the fixup, up to and including the
// rebase start commit, see if we find the base commit
for _, baseCommit := range commits[i+1 : rebaseStartIdx+1] {
if strings.HasPrefix(baseCommit.Name, baseSubject) {
result++
}
}
}
}
return result
}
// Check whether the given subject line is the subject of a fixup commit, and
// returns (trimmedSubject, true) if so (where trimmedSubject is the subject
// with all fixup prefixes removed), or (subject, false) if not.
func isFixupCommit(subject string) (string, bool) {
prefixes := []string{"fixup! ", "squash! ", "amend! "}
trimPrefix := func(s string) (string, bool) {
for _, prefix := range prefixes {
if strings.HasPrefix(s, prefix) {
return strings.TrimPrefix(s, prefix), true
}
}
return s, false
}
if subject, wasTrimmed := trimPrefix(subject); wasTrimmed {
for {
// handle repeated prefixes like "fixup! amend! fixup! Subject"
if subject, wasTrimmed = trimPrefix(subject); !wasTrimmed {
break
}
}
return subject, true
}
return subject, false
return commits[index-1], nil
}
func (self *LocalCommitsController) createTag(commit *models.Commit) error {
@@ -1125,7 +1062,7 @@ func (self *LocalCommitsController) canFindCommitForQuickStart() *types.Disabled
}
func (self *LocalCommitsController) canFindCommitForSquashFixupsInCurrentBranch() *types.DisabledReason {
if _, _, err := self.findCommitForSquashFixupsInCurrentBranch(); err != nil {
if _, err := self.findCommitForSquashFixupsInCurrentBranch(); err != nil {
return &types.DisabledReason{Text: err.Error()}
}
@@ -1,141 +0,0 @@
package controllers
import (
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/stretchr/testify/assert"
)
func Test_countSquashableCommitsAbove(t *testing.T) {
scenarios := []struct {
name string
commits []*models.Commit
selectedIdx int
rebaseStartIdx int
expectedResult int
}{
{
name: "no squashable commits",
commits: []*models.Commit{
{Name: "abc"},
{Name: "def"},
{Name: "ghi"},
},
selectedIdx: 2,
rebaseStartIdx: 2,
expectedResult: 0,
},
{
name: "some squashable commits, including for the selected commit",
commits: []*models.Commit{
{Name: "fixup! def"},
{Name: "fixup! ghi"},
{Name: "abc"},
{Name: "def"},
{Name: "ghi"},
},
selectedIdx: 4,
rebaseStartIdx: 4,
expectedResult: 2,
},
{
name: "base commit is below rebase start",
commits: []*models.Commit{
{Name: "fixup! def"},
{Name: "abc"},
{Name: "def"},
},
selectedIdx: 1,
rebaseStartIdx: 1,
expectedResult: 0,
},
{
name: "base commit does not exist at all",
commits: []*models.Commit{
{Name: "fixup! xyz"},
{Name: "abc"},
{Name: "def"},
},
selectedIdx: 2,
rebaseStartIdx: 2,
expectedResult: 0,
},
{
name: "selected commit is in the middle of fixups",
commits: []*models.Commit{
{Name: "fixup! def"},
{Name: "abc"},
{Name: "fixup! ghi"},
{Name: "def"},
{Name: "ghi"},
},
selectedIdx: 1,
rebaseStartIdx: 4,
expectedResult: 1,
},
{
name: "selected commit is after rebase start",
commits: []*models.Commit{
{Name: "fixup! def"},
{Name: "abc"},
{Name: "def"},
{Name: "ghi"},
},
selectedIdx: 3,
rebaseStartIdx: 2,
expectedResult: 1,
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
assert.Equal(t, s.expectedResult, countSquashableCommitsAbove(s.commits, s.selectedIdx, s.rebaseStartIdx))
})
}
}
func Test_isFixupCommit(t *testing.T) {
scenarios := []struct {
subject string
expectedTrimmedSubject string
expectedIsFixup bool
}{
{
subject: "Bla",
expectedTrimmedSubject: "Bla",
expectedIsFixup: false,
},
{
subject: "fixup Bla",
expectedTrimmedSubject: "fixup Bla",
expectedIsFixup: false,
},
{
subject: "fixup! Bla",
expectedTrimmedSubject: "Bla",
expectedIsFixup: true,
},
{
subject: "fixup! fixup! Bla",
expectedTrimmedSubject: "Bla",
expectedIsFixup: true,
},
{
subject: "amend! squash! Bla",
expectedTrimmedSubject: "Bla",
expectedIsFixup: true,
},
{
subject: "fixup!",
expectedTrimmedSubject: "fixup!",
expectedIsFixup: false,
},
}
for _, s := range scenarios {
t.Run(s.subject, func(t *testing.T) {
trimmedSubject, isFixupCommit := isFixupCommit(s.subject)
assert.Equal(t, s.expectedTrimmedSubject, trimmedSubject)
assert.Equal(t, s.expectedIsFixup, isFixupCommit)
})
}
}
-2
View File
@@ -168,8 +168,6 @@ func (gui *Gui) createAllViews() error {
gui.Views.CommitDescription.FgColor = theme.GocuiDefaultTextColor
gui.Views.CommitDescription.Editable = true
gui.Views.CommitDescription.Editor = gocui.EditorFunc(gui.commitDescriptionEditor)
gui.Views.CommitDescription.TextArea.AutoWrap = gui.c.UserConfig.Git.Commit.AutoWrapCommitMessage
gui.Views.CommitDescription.TextArea.AutoWrapWidth = gui.c.UserConfig.Git.Commit.AutoWrapWidth
gui.Views.Confirmation.Visible = false
gui.Views.Confirmation.Editor = gocui.EditorFunc(gui.promptEditor)
-2
View File
@@ -341,7 +341,6 @@ type TranslationSet struct {
CheckingOutStatus string
CommittingStatus string
RevertingStatus string
CreatingFixupCommitStatus string
CommitFiles string
SubCommitsDynamicTitle string
CommitFilesDynamicTitle string
@@ -1290,7 +1289,6 @@ func EnglishTranslationSet() TranslationSet {
CheckingOutStatus: "Checking out",
CommittingStatus: "Committing",
RevertingStatus: "Reverting",
CreatingFixupCommitStatus: "Creating fixup commit",
CommitFiles: "Commit files",
SubCommitsDynamicTitle: "Commits (%s)",
CommitFilesDynamicTitle: "Diff files (%s)",
@@ -31,16 +31,6 @@ func (self *CommitDescriptionPanelDriver) AddNewline() *CommitDescriptionPanelDr
return self
}
func (self *CommitDescriptionPanelDriver) GoToBeginning() *CommitDescriptionPanelDriver {
numLines := len(self.getViewDriver().getView().BufferLines())
for i := 0; i < numLines; i++ {
self.t.pressFast("<up>")
}
self.t.pressFast("<c-a>")
return self
}
func (self *CommitDescriptionPanelDriver) Title(expected *TextMatcher) *CommitDescriptionPanelDriver {
self.getViewDriver().Title(expected)
+4
View File
@@ -148,6 +148,10 @@ func (self *Shell) Checkout(name string) *Shell {
return self.RunCommand([]string{"git", "checkout", name})
}
func (self *Shell) DeleteBranch(name string) *Shell {
return self.RunCommand([]string{"git", "branch", "-D", name})
}
func (self *Shell) Merge(name string) *Shell {
return self.RunCommand([]string{"git", "merge", "--commit", "--no-ff", name})
}
@@ -0,0 +1,66 @@
package branch
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var CheckoutByNameRemote = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Checkout a remote branch by name, both using the full name and the local name.",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("initial commit")
// create an origin/foo remote branch
shell.CloneIntoRemote("origin")
shell.NewBranch("foo")
shell.PushBranch("origin", "foo")
// delete the local version of the branch because we need to test checking it out from scratch
shell.Checkout("master")
shell.DeleteBranch("foo")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Branches().
Focus().
Lines(
Contains("master").IsSelected(),
).
// maximising window so that we can see the tracked branch
Press(keys.Universal.NextScreenMode).
Press(keys.Branches.CheckoutBranchByName).
Tap(func() {
t.ExpectPopup().Prompt().
Title(Equals("Branch name:")).
Type("foo").
SuggestionLines(
Contains("foo"),
Contains("origin/foo"),
).
ConfirmFirstSuggestion()
}).
Lines(
Contains("foo").
// we have not checked out origin/foo...
DoesNotContain("origin/foo").
// ... but we are tracking it (formatted as '<remote> <branch>')
Contains("origin foo"),
Contains("master"),
).
Press(keys.Branches.CheckoutBranchByName).
Tap(func() {
t.ExpectPopup().Prompt().
Title(Equals("Branch name:")).
Type("origin/foo").
SuggestionLines(
Contains("origin/foo"),
).
ConfirmFirstSuggestion()
}).
Lines(
Contains("HEAD detached at origin/foo"),
Contains("foo"),
Contains("master"),
)
},
})
@@ -1,59 +0,0 @@
package commit
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var AutoWrapMessage = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Commit, and test how the commit message body is auto-wrapped",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
// Use a ridiculously small width so that we don't have to use so much test data
config.UserConfig.Git.Commit.AutoWrapWidth = 20
},
SetupRepo: func(shell *Shell) {
shell.CreateFile("file", "file content")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
IsEmpty()
t.Views().Files().
IsFocused().
PressPrimaryAction(). // stage file
Press(keys.Files.CommitChanges)
t.ExpectPopup().CommitMessagePanel().
Type("subject").
SwitchToDescription().
Type("Lorem ipsum dolor sit amet, consectetur adipiscing elit.").
// See how it automatically inserted line feeds to wrap the text:
Content(Equals("Lorem ipsum dolor \nsit amet, \nconsectetur \nadipiscing elit.")).
SwitchToSummary().
Confirm()
t.Views().Commits().
Lines(
Contains("subject"),
).
Focus().
Tap(func() {
t.Views().Main().Content(Contains(
"subject\n \n Lorem ipsum dolor\n sit amet,\n consectetur\n adipiscing elit."))
}).
Press(keys.Commits.RenameCommit)
// Test that when rewording, the hard line breaks are turned back into
// soft ones, so that we can insert text at the beginning and have the
// paragraph reflow nicely.
t.ExpectPopup().CommitMessagePanel().
InitialText(Equals("subject")).
SwitchToDescription().
Content(Equals("Lorem ipsum dolor \nsit amet, \nconsectetur \nadipiscing elit.")).
GoToBeginning().
Type("More text. ").
Content(Equals("More text. Lorem \nipsum dolor sit \namet, consectetur \nadipiscing elit."))
},
})
@@ -1,51 +0,0 @@
package interactive_rebase
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
)
var EditRangeSelectOutsideRebase = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Select a range of commits to edit outside of a rebase",
ExtraCmdArgs: []string{},
Skip: false,
GitVersion: AtLeast("2.22.0"), // first version that supports the --rebase-merges option
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shared.CreateMergeCommit(shell)
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
TopLines(
Contains("Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
).
Press(keys.Universal.RangeSelectDown).
Press(keys.Universal.RangeSelectDown).
Press(keys.Universal.RangeSelectDown).
Press(keys.Universal.RangeSelectDown).
Press(keys.Universal.RangeSelectDown).
Lines(
Contains("CI ⏣─╮ Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
Contains("CI │ ◯ * second-change-branch unrelated change").IsSelected(),
Contains("CI │ ◯ second change").IsSelected(),
Contains("CI ◯ │ first change").IsSelected(),
Contains("CI ◯─╯ * original").IsSelected(),
Contains("CI ◯ three").IsSelected(),
Contains("CI ◯ two"),
Contains("CI ◯ one"),
).
Press(keys.Universal.Edit).
Lines(
Contains("merge CI Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
Contains("edit CI first change").IsSelected(),
Contains("edit CI * second-change-branch unrelated change").IsSelected(),
Contains("edit CI second change").IsSelected(),
Contains("edit CI * original").IsSelected(),
Contains(" CI ◯ <-- YOU ARE HERE --- three").IsSelected(),
Contains(" CI ◯ two"),
Contains(" CI ◯ one"),
)
},
})
@@ -20,6 +20,27 @@ var MidRebaseRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
TopLines(
Contains("commit 10").IsSelected(),
).
NavigateToLine(Contains("commit 07")).
Press(keys.Universal.RangeSelectDown).
TopLines(
Contains("commit 10"),
Contains("commit 09"),
Contains("commit 08"),
Contains("commit 07").IsSelected(),
Contains("commit 06").IsSelected(),
Contains("commit 05"),
Contains("commit 04"),
).
// Verify we can't perform an edit on multiple commits (it's not supported
// yet)
Press(keys.Universal.Edit).
Tap(func() {
// This ought to be a toast but I'm too lazy to implement that right now.
t.ExpectPopup().Alert().
Title(Equals("Error")).
Content(Contains("Action does not support range selection, please select a single item")).
Confirm()
}).
NavigateToLine(Contains("commit 05")).
// Start a rebase
Press(keys.Universal.Edit).
@@ -1,56 +0,0 @@
package interactive_rebase
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var SquashFixupsAbove = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Squashes all fixups above a commit and checks that the selected line stays correct.",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.
CreateNCommits(3).
CreateFileAndAdd("fixup-file", "fixup content")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("commit 03"),
Contains("commit 02"),
Contains("commit 01"),
).
NavigateToLine(Contains("commit 02")).
Press(keys.Commits.CreateFixupCommit).
Tap(func() {
t.ExpectPopup().Confirmation().
Title(Equals("Create fixup commit")).
Content(Contains("Are you sure you want to create a fixup! commit for commit")).
Confirm()
}).
Lines(
Contains("fixup! commit 02"),
Contains("commit 03"),
Contains("commit 02").IsSelected(),
Contains("commit 01"),
).
Press(keys.Commits.SquashAboveCommits).
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Apply fixup commits")).
Select(Contains("Above the selected commit")).
Confirm()
}).
Lines(
Contains("commit 03"),
Contains("commit 02").IsSelected(),
Contains("commit 01"),
)
t.Views().Main().
Content(Contains("fixup content"))
},
})
@@ -27,12 +27,10 @@ var SquashFixupsInCurrentBranch = NewIntegrationTest(NewIntegrationTestArgs{
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
SelectNextItem().
SelectNextItem().
Lines(
Contains("fixup! commit 01"),
Contains("commit 02"),
Contains("commit 01").IsSelected(),
Contains("commit 01"),
Contains("fixup! master commit"),
Contains("master commit"),
).
@@ -45,10 +43,11 @@ var SquashFixupsInCurrentBranch = NewIntegrationTest(NewIntegrationTestArgs{
}).
Lines(
Contains("commit 02"),
Contains("commit 01").IsSelected(),
Contains("commit 01"),
Contains("fixup! master commit"),
Contains("master commit"),
)
).
NavigateToLine(Contains("commit 01"))
t.Views().Main().
Content(Contains("fixup content"))
+1 -3
View File
@@ -37,6 +37,7 @@ var tests = []*components.IntegrationTest{
bisect.FromOtherBranch,
bisect.Skip,
branch.CheckoutByName,
branch.CheckoutByNameRemote,
branch.CreateTag,
branch.Delete,
branch.DeleteRemoteBranchWithCredentialPrompt,
@@ -65,7 +66,6 @@ var tests = []*components.IntegrationTest{
cherry_pick.CherryPickRange,
commit.AddCoAuthor,
commit.Amend,
commit.AutoWrapMessage,
commit.Commit,
commit.CommitMultiline,
commit.CommitSwitchToEditor,
@@ -168,7 +168,6 @@ var tests = []*components.IntegrationTest{
interactive_rebase.DropWithCustomCommentChar,
interactive_rebase.EditFirstCommit,
interactive_rebase.EditNonTodoCommitDuringRebase,
interactive_rebase.EditRangeSelectOutsideRebase,
interactive_rebase.EditTheConflCommit,
interactive_rebase.FixupFirstCommit,
interactive_rebase.FixupSecondCommit,
@@ -189,7 +188,6 @@ var tests = []*components.IntegrationTest{
interactive_rebase.RewordYouAreHereCommitWithEditor,
interactive_rebase.SquashDownFirstCommit,
interactive_rebase.SquashDownSecondCommit,
interactive_rebase.SquashFixupsAbove,
interactive_rebase.SquashFixupsAboveFirstCommit,
interactive_rebase.SquashFixupsInCurrentBranch,
interactive_rebase.SwapInRebaseWithConflict,
-10
View File
@@ -405,16 +405,6 @@
"signOff": {
"type": "boolean",
"description": "If true, pass '--signoff' flag when committing"
},
"autoWrapCommitMessage": {
"type": "boolean",
"description": "Automatic WYSIWYG wrapping of the commit message as you type",
"default": true
},
"autoWrapWidth": {
"type": "integer",
"description": "If autoWrapCommitMessage is true, the width to wrap to",
"default": 72
}
},
"additionalProperties": false,
+3 -3
View File
@@ -341,12 +341,12 @@ func (s *cScreen) disengage() {
}
} else if !s.disableAlt {
s.clearScreen(StyleDefault, s.vten)
s.setCursorPos(0, 0, false)
}
s.setCursorInfo(&s.ocursor)
s.setBufferSize(int(s.oscreen.size.x), int(s.oscreen.size.y))
s.setInMode(s.oimode)
s.setOutMode(s.oomode)
s.setBufferSize(int(s.oscreen.size.x), int(s.oscreen.size.y))
s.setCursorPos(0, 0, false)
s.setCursorInfo(&s.ocursor)
_, _, _ = procSetConsoleTextAttribute.Call(
uintptr(s.out),
uintptr(s.mapStyle(StyleDefault)))
+14 -154
View File
@@ -11,59 +11,11 @@ const (
WORD_SEPARATORS = "*?_+-.[]~=/&;!#$%^(){}<>"
)
type CursorMapping struct {
Orig int
Wrapped int
}
type TextArea struct {
content []rune
wrappedContent []rune
cursorMapping []CursorMapping
cursor int
overwrite bool
clipboard string
AutoWrap bool
AutoWrapWidth int
}
func AutoWrapContent(content []rune, autoWrapWidth int) ([]rune, []CursorMapping) {
estimatedNumberOfSoftLineBreaks := len(content) / autoWrapWidth
cursorMapping := make([]CursorMapping, 0, estimatedNumberOfSoftLineBreaks)
wrappedContent := make([]rune, 0, len(content)+estimatedNumberOfSoftLineBreaks)
startOfLine := 0
indexOfLastWhitespace := -1
for currentPos, r := range content {
if r == '\n' {
wrappedContent = append(wrappedContent, content[startOfLine:currentPos+1]...)
startOfLine = currentPos + 1
indexOfLastWhitespace = -1
} else {
if r == ' ' {
indexOfLastWhitespace = currentPos + 1
} else if currentPos-startOfLine >= autoWrapWidth && indexOfLastWhitespace >= 0 {
wrapAt := indexOfLastWhitespace
wrappedContent = append(wrappedContent, content[startOfLine:wrapAt]...)
wrappedContent = append(wrappedContent, '\n')
cursorMapping = append(cursorMapping, CursorMapping{wrapAt, len(wrappedContent)})
startOfLine = wrapAt
indexOfLastWhitespace = -1
}
}
}
wrappedContent = append(wrappedContent, content[startOfLine:]...)
return wrappedContent, cursorMapping
}
func (self *TextArea) autoWrapContent() {
if self.AutoWrap {
self.wrappedContent, self.cursorMapping = AutoWrapContent(self.content, self.AutoWrapWidth)
} else {
self.wrappedContent, self.cursorMapping = self.content, []CursorMapping{}
}
content []rune
cursor int
overwrite bool
clipboard string
}
func (self *TextArea) TypeRune(r rune) {
@@ -75,7 +27,6 @@ func (self *TextArea) TypeRune(r rune) {
append([]rune{r}, self.content[self.cursor:]...)...,
)
}
self.autoWrapContent()
self.cursor++
}
@@ -86,7 +37,6 @@ func (self *TextArea) BackSpaceChar() {
}
self.content = append(self.content[:self.cursor-1], self.content[self.cursor:]...)
self.autoWrapContent()
self.cursor--
}
@@ -96,7 +46,6 @@ func (self *TextArea) DeleteChar() {
}
self.content = append(self.content[:self.cursor], self.content[self.cursor+1:]...)
self.autoWrapContent()
}
func (self *TextArea) MoveCursorLeft() {
@@ -174,10 +123,6 @@ func (self *TextArea) MoveCursorDown() {
}
func (self *TextArea) GetContent() string {
return string(self.wrappedContent)
}
func (self *TextArea) GetUnwrappedContent() string {
return string(self.content)
}
@@ -199,24 +144,14 @@ func (self *TextArea) DeleteToStartOfLine() {
self.content = append(self.content[:self.cursor-1], self.content[self.cursor:]...)
self.cursor--
self.autoWrapContent()
return
}
// otherwise, if we're at a soft line start, skip left past the soft line
// break, so we'll end up deleting the previous line. This seems like the
// only reasonable behavior in this case, as you can't delete just the soft
// line break.
if self.atSoftLineStart() {
self.cursor--
}
// otherwise, you delete everything up to the start of the current line, without
// deleting the newline character
newlineIndex := self.closestNewlineOnLeft()
self.clipboard = string(self.content[newlineIndex+1 : self.cursor])
self.content = append(self.content[:newlineIndex+1], self.content[self.cursor:]...)
self.autoWrapContent()
self.cursor = newlineIndex + 1
}
@@ -224,30 +159,18 @@ func (self *TextArea) DeleteToEndOfLine() {
if self.atEnd() {
return
}
// if we're at the end of the line, delete just the newline character
if self.atLineEnd() {
self.content = append(self.content[:self.cursor], self.content[self.cursor+1:]...)
self.autoWrapContent()
return
}
// otherwise, if we're at a soft line end, skip right past the soft line
// break, so we'll end up deleting the next line. This seems like the
// only reasonable behavior in this case, as you can't delete just the soft
// line break.
if self.atSoftLineEnd() {
self.cursor++
}
lineEndIndex := self.closestNewlineOnRight()
self.clipboard = string(self.content[self.cursor:lineEndIndex])
self.content = append(self.content[:self.cursor], self.content[lineEndIndex:]...)
self.autoWrapContent()
}
func (self *TextArea) GoToStartOfLine() {
if self.atSoftLineStart() {
if self.atLineStart() {
return
}
@@ -258,21 +181,15 @@ func (self *TextArea) GoToStartOfLine() {
}
func (self *TextArea) closestNewlineOnLeft() int {
wrappedCursor := self.origCursorToWrappedCursor(self.cursor)
newlineIndex := -1
for i, r := range self.wrappedContent[0:wrappedCursor] {
for i, r := range self.content[0:self.cursor] {
if r == '\n' {
newlineIndex = i
}
}
unwrappedNewlineIndex := self.wrappedCursorToOrigCursor(newlineIndex)
if unwrappedNewlineIndex >= 0 && self.content[unwrappedNewlineIndex] != '\n' {
unwrappedNewlineIndex--
}
return unwrappedNewlineIndex
return newlineIndex
}
func (self *TextArea) GoToEndOfLine() {
@@ -281,22 +198,12 @@ func (self *TextArea) GoToEndOfLine() {
}
self.cursor = self.closestNewlineOnRight()
// If the end of line is a soft line break, we need to move left by one so
// that we end up at the last whitespace before the line break. Otherwise
// we'd be at the start of the next line, since the newline character
// doesn't really exist in the real content.
if self.cursor < len(self.content) && self.content[self.cursor] != '\n' {
self.cursor--
}
}
func (self *TextArea) closestNewlineOnRight() int {
wrappedCursor := self.origCursorToWrappedCursor(self.cursor)
for i, r := range self.wrappedContent[wrappedCursor:] {
for i, r := range self.content[self.cursor:] {
if r == '\n' {
return self.wrappedCursorToOrigCursor(wrappedCursor + i)
return self.cursor + i
}
}
@@ -308,23 +215,11 @@ func (self *TextArea) atLineStart() bool {
(len(self.content) > self.cursor-1 && self.content[self.cursor-1] == '\n')
}
func (self *TextArea) atSoftLineStart() bool {
wrappedCursor := self.origCursorToWrappedCursor(self.cursor)
return wrappedCursor == 0 ||
(len(self.wrappedContent) > wrappedCursor-1 && self.wrappedContent[wrappedCursor-1] == '\n')
}
func (self *TextArea) atLineEnd() bool {
return self.atEnd() ||
(len(self.content) > self.cursor && self.content[self.cursor] == '\n')
}
func (self *TextArea) atSoftLineEnd() bool {
wrappedCursor := self.origCursorToWrappedCursor(self.cursor)
return wrappedCursor == len(self.wrappedContent) ||
(len(self.wrappedContent) > wrappedCursor+1 && self.wrappedContent[wrappedCursor+1] == '\n')
}
func (self *TextArea) BackSpaceWord() {
if self.cursor == 0 {
return
@@ -351,50 +246,16 @@ func (self *TextArea) BackSpaceWord() {
self.clipboard = string(self.content[self.cursor:right])
self.content = append(self.content[:self.cursor], self.content[right:]...)
self.autoWrapContent()
}
func (self *TextArea) Yank() {
self.TypeString(self.clipboard)
}
func origCursorToWrappedCursor(origCursor int, cursorMapping []CursorMapping) int {
prevMapping := CursorMapping{0, 0}
for _, mapping := range cursorMapping {
if origCursor < mapping.Orig {
break
}
prevMapping = mapping
}
return origCursor + prevMapping.Wrapped - prevMapping.Orig
}
func (self *TextArea) origCursorToWrappedCursor(origCursor int) int {
return origCursorToWrappedCursor(origCursor, self.cursorMapping)
}
func wrappedCursorToOrigCursor(wrappedCursor int, cursorMapping []CursorMapping) int {
prevMapping := CursorMapping{0, 0}
for _, mapping := range cursorMapping {
if wrappedCursor < mapping.Wrapped {
break
}
prevMapping = mapping
}
return wrappedCursor + prevMapping.Orig - prevMapping.Wrapped
}
func (self *TextArea) wrappedCursorToOrigCursor(wrappedCursor int) int {
return wrappedCursorToOrigCursor(wrappedCursor, self.cursorMapping)
}
func (self *TextArea) GetCursorXY() (int, int) {
cursorX := 0
cursorY := 0
wrappedCursor := self.origCursorToWrappedCursor(self.cursor)
for _, r := range self.wrappedContent[0:wrappedCursor] {
for _, r := range self.content[0:self.cursor] {
if r == '\n' {
cursorY++
cursorX = 0
@@ -417,15 +278,15 @@ func (self *TextArea) SetCursor2D(x int, y int) {
}
newCursor := 0
for _, r := range self.wrappedContent {
for _, r := range self.content {
if x <= 0 && y == 0 {
self.cursor = self.wrappedCursorToOrigCursor(newCursor)
self.cursor = newCursor
return
}
if r == '\n' {
if y == 0 {
self.cursor = self.wrappedCursorToOrigCursor(newCursor)
self.cursor = newCursor
return
}
y--
@@ -443,12 +304,11 @@ func (self *TextArea) SetCursor2D(x int, y int) {
return
}
self.cursor = self.wrappedCursorToOrigCursor(newCursor)
self.cursor = newCursor
}
func (self *TextArea) Clear() {
self.content = []rune{}
self.wrappedContent = []rune{}
self.cursor = 0
}
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9
package unix
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin
//go:build darwin && go1.12
package unix
+5 -7
View File
@@ -13,7 +13,6 @@
package unix
import (
"errors"
"sync"
"unsafe"
)
@@ -170,26 +169,25 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
func Uname(uname *Utsname) error {
mib := []_C_int{CTL_KERN, KERN_OSTYPE}
n := unsafe.Sizeof(uname.Sysname)
// Suppress ENOMEM errors to be compatible with the C library __xuname() implementation.
if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil {
return err
}
mib = []_C_int{CTL_KERN, KERN_HOSTNAME}
n = unsafe.Sizeof(uname.Nodename)
if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil {
return err
}
mib = []_C_int{CTL_KERN, KERN_OSRELEASE}
n = unsafe.Sizeof(uname.Release)
if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil {
return err
}
mib = []_C_int{CTL_KERN, KERN_VERSION}
n = unsafe.Sizeof(uname.Version)
if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil {
return err
}
@@ -207,7 +205,7 @@ func Uname(uname *Utsname) error {
mib = []_C_int{CTL_HW, HW_MACHINE}
n = unsafe.Sizeof(uname.Machine)
if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil {
return err
}
-99
View File
@@ -1849,105 +1849,6 @@ func Dup2(oldfd, newfd int) error {
//sys Fsmount(fd int, flags int, mountAttrs int) (fsfd int, err error)
//sys Fsopen(fsName string, flags int) (fd int, err error)
//sys Fspick(dirfd int, pathName string, flags int) (fd int, err error)
//sys fsconfig(fd int, cmd uint, key *byte, value *byte, aux int) (err error)
func fsconfigCommon(fd int, cmd uint, key string, value *byte, aux int) (err error) {
var keyp *byte
if keyp, err = BytePtrFromString(key); err != nil {
return
}
return fsconfig(fd, cmd, keyp, value, aux)
}
// FsconfigSetFlag is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_FLAG.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
func FsconfigSetFlag(fd int, key string) (err error) {
return fsconfigCommon(fd, FSCONFIG_SET_FLAG, key, nil, 0)
}
// FsconfigSetString is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_STRING.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
// value is the parameter value to set.
func FsconfigSetString(fd int, key string, value string) (err error) {
var valuep *byte
if valuep, err = BytePtrFromString(value); err != nil {
return
}
return fsconfigCommon(fd, FSCONFIG_SET_STRING, key, valuep, 0)
}
// FsconfigSetBinary is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_BINARY.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
// value is the parameter value to set.
func FsconfigSetBinary(fd int, key string, value []byte) (err error) {
if len(value) == 0 {
return EINVAL
}
return fsconfigCommon(fd, FSCONFIG_SET_BINARY, key, &value[0], len(value))
}
// FsconfigSetPath is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_PATH.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
// path is a non-empty path for specified key.
// atfd is a file descriptor at which to start lookup from or AT_FDCWD.
func FsconfigSetPath(fd int, key string, path string, atfd int) (err error) {
var valuep *byte
if valuep, err = BytePtrFromString(path); err != nil {
return
}
return fsconfigCommon(fd, FSCONFIG_SET_PATH, key, valuep, atfd)
}
// FsconfigSetPathEmpty is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_PATH_EMPTY. The same as
// FconfigSetPath but with AT_PATH_EMPTY implied.
func FsconfigSetPathEmpty(fd int, key string, path string, atfd int) (err error) {
var valuep *byte
if valuep, err = BytePtrFromString(path); err != nil {
return
}
return fsconfigCommon(fd, FSCONFIG_SET_PATH_EMPTY, key, valuep, atfd)
}
// FsconfigSetFd is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_FD.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
// value is a file descriptor to be assigned to specified key.
func FsconfigSetFd(fd int, key string, value int) (err error) {
return fsconfigCommon(fd, FSCONFIG_SET_FD, key, nil, value)
}
// FsconfigCreate is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_CMD_CREATE.
//
// fd is the filesystem context to act upon.
func FsconfigCreate(fd int) (err error) {
return fsconfig(fd, FSCONFIG_CMD_CREATE, nil, nil, 0)
}
// FsconfigReconfigure is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_CMD_RECONFIGURE.
//
// fd is the filesystem context to act upon.
func FsconfigReconfigure(fd int) (err error) {
return fsconfig(fd, FSCONFIG_CMD_RECONFIGURE, nil, nil, 0)
}
//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
//sysnb Getpgid(pid int) (pgid int, err error)
-10
View File
@@ -906,16 +906,6 @@ func Fspick(dirfd int, pathName string, flags int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fsconfig(fd int, cmd uint, key *byte, value *byte, aux int) (err error) {
_, _, e1 := Syscall6(SYS_FSCONFIG, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(value)), uintptr(aux), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getdents(fd int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
-60
View File
@@ -836,15 +836,6 @@ const (
FSPICK_EMPTY_PATH = 0x8
FSMOUNT_CLOEXEC = 0x1
FSCONFIG_SET_FLAG = 0x0
FSCONFIG_SET_STRING = 0x1
FSCONFIG_SET_BINARY = 0x2
FSCONFIG_SET_PATH = 0x3
FSCONFIG_SET_PATH_EMPTY = 0x4
FSCONFIG_SET_FD = 0x5
FSCONFIG_CMD_CREATE = 0x6
FSCONFIG_CMD_RECONFIGURE = 0x7
)
type OpenHow struct {
@@ -1559,7 +1550,6 @@ const (
IFLA_DEVLINK_PORT = 0x3e
IFLA_GSO_IPV4_MAX_SIZE = 0x3f
IFLA_GRO_IPV4_MAX_SIZE = 0x40
IFLA_DPLL_PIN = 0x41
IFLA_PROTO_DOWN_REASON_UNSPEC = 0x0
IFLA_PROTO_DOWN_REASON_MASK = 0x1
IFLA_PROTO_DOWN_REASON_VALUE = 0x2
@@ -1575,7 +1565,6 @@ const (
IFLA_INET6_ICMP6STATS = 0x6
IFLA_INET6_TOKEN = 0x7
IFLA_INET6_ADDR_GEN_MODE = 0x8
IFLA_INET6_RA_MTU = 0x9
IFLA_BR_UNSPEC = 0x0
IFLA_BR_FORWARD_DELAY = 0x1
IFLA_BR_HELLO_TIME = 0x2
@@ -1623,9 +1612,6 @@ const (
IFLA_BR_MCAST_MLD_VERSION = 0x2c
IFLA_BR_VLAN_STATS_PER_PORT = 0x2d
IFLA_BR_MULTI_BOOLOPT = 0x2e
IFLA_BR_MCAST_QUERIER_STATE = 0x2f
IFLA_BR_FDB_N_LEARNED = 0x30
IFLA_BR_FDB_MAX_LEARNED = 0x31
IFLA_BRPORT_UNSPEC = 0x0
IFLA_BRPORT_STATE = 0x1
IFLA_BRPORT_PRIORITY = 0x2
@@ -1663,14 +1649,6 @@ const (
IFLA_BRPORT_BACKUP_PORT = 0x22
IFLA_BRPORT_MRP_RING_OPEN = 0x23
IFLA_BRPORT_MRP_IN_OPEN = 0x24
IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT = 0x25
IFLA_BRPORT_MCAST_EHT_HOSTS_CNT = 0x26
IFLA_BRPORT_LOCKED = 0x27
IFLA_BRPORT_MAB = 0x28
IFLA_BRPORT_MCAST_N_GROUPS = 0x29
IFLA_BRPORT_MCAST_MAX_GROUPS = 0x2a
IFLA_BRPORT_NEIGH_VLAN_SUPPRESS = 0x2b
IFLA_BRPORT_BACKUP_NHID = 0x2c
IFLA_INFO_UNSPEC = 0x0
IFLA_INFO_KIND = 0x1
IFLA_INFO_DATA = 0x2
@@ -1692,9 +1670,6 @@ const (
IFLA_MACVLAN_MACADDR = 0x4
IFLA_MACVLAN_MACADDR_DATA = 0x5
IFLA_MACVLAN_MACADDR_COUNT = 0x6
IFLA_MACVLAN_BC_QUEUE_LEN = 0x7
IFLA_MACVLAN_BC_QUEUE_LEN_USED = 0x8
IFLA_MACVLAN_BC_CUTOFF = 0x9
IFLA_VRF_UNSPEC = 0x0
IFLA_VRF_TABLE = 0x1
IFLA_VRF_PORT_UNSPEC = 0x0
@@ -1718,22 +1693,9 @@ const (
IFLA_XFRM_UNSPEC = 0x0
IFLA_XFRM_LINK = 0x1
IFLA_XFRM_IF_ID = 0x2
IFLA_XFRM_COLLECT_METADATA = 0x3
IFLA_IPVLAN_UNSPEC = 0x0
IFLA_IPVLAN_MODE = 0x1
IFLA_IPVLAN_FLAGS = 0x2
NETKIT_NEXT = -0x1
NETKIT_PASS = 0x0
NETKIT_DROP = 0x2
NETKIT_REDIRECT = 0x7
NETKIT_L2 = 0x0
NETKIT_L3 = 0x1
IFLA_NETKIT_UNSPEC = 0x0
IFLA_NETKIT_PEER_INFO = 0x1
IFLA_NETKIT_PRIMARY = 0x2
IFLA_NETKIT_POLICY = 0x3
IFLA_NETKIT_PEER_POLICY = 0x4
IFLA_NETKIT_MODE = 0x5
IFLA_VXLAN_UNSPEC = 0x0
IFLA_VXLAN_ID = 0x1
IFLA_VXLAN_GROUP = 0x2
@@ -1764,8 +1726,6 @@ const (
IFLA_VXLAN_GPE = 0x1b
IFLA_VXLAN_TTL_INHERIT = 0x1c
IFLA_VXLAN_DF = 0x1d
IFLA_VXLAN_VNIFILTER = 0x1e
IFLA_VXLAN_LOCALBYPASS = 0x1f
IFLA_GENEVE_UNSPEC = 0x0
IFLA_GENEVE_ID = 0x1
IFLA_GENEVE_REMOTE = 0x2
@@ -1780,7 +1740,6 @@ const (
IFLA_GENEVE_LABEL = 0xb
IFLA_GENEVE_TTL_INHERIT = 0xc
IFLA_GENEVE_DF = 0xd
IFLA_GENEVE_INNER_PROTO_INHERIT = 0xe
IFLA_BAREUDP_UNSPEC = 0x0
IFLA_BAREUDP_PORT = 0x1
IFLA_BAREUDP_ETHERTYPE = 0x2
@@ -1793,8 +1752,6 @@ const (
IFLA_GTP_FD1 = 0x2
IFLA_GTP_PDP_HASHSIZE = 0x3
IFLA_GTP_ROLE = 0x4
IFLA_GTP_CREATE_SOCKETS = 0x5
IFLA_GTP_RESTART_COUNT = 0x6
IFLA_BOND_UNSPEC = 0x0
IFLA_BOND_MODE = 0x1
IFLA_BOND_ACTIVE_SLAVE = 0x2
@@ -1824,9 +1781,6 @@ const (
IFLA_BOND_AD_ACTOR_SYSTEM = 0x1a
IFLA_BOND_TLB_DYNAMIC_LB = 0x1b
IFLA_BOND_PEER_NOTIF_DELAY = 0x1c
IFLA_BOND_AD_LACP_ACTIVE = 0x1d
IFLA_BOND_MISSED_MAX = 0x1e
IFLA_BOND_NS_IP6_TARGET = 0x1f
IFLA_BOND_AD_INFO_UNSPEC = 0x0
IFLA_BOND_AD_INFO_AGGREGATOR = 0x1
IFLA_BOND_AD_INFO_NUM_PORTS = 0x2
@@ -1842,7 +1796,6 @@ const (
IFLA_BOND_SLAVE_AD_AGGREGATOR_ID = 0x6
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE = 0x7
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE = 0x8
IFLA_BOND_SLAVE_PRIO = 0x9
IFLA_VF_INFO_UNSPEC = 0x0
IFLA_VF_INFO = 0x1
IFLA_VF_UNSPEC = 0x0
@@ -1901,16 +1854,8 @@ const (
IFLA_STATS_LINK_XSTATS_SLAVE = 0x3
IFLA_STATS_LINK_OFFLOAD_XSTATS = 0x4
IFLA_STATS_AF_SPEC = 0x5
IFLA_STATS_GETSET_UNSPEC = 0x0
IFLA_STATS_GET_FILTERS = 0x1
IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS = 0x2
IFLA_OFFLOAD_XSTATS_UNSPEC = 0x0
IFLA_OFFLOAD_XSTATS_CPU_HIT = 0x1
IFLA_OFFLOAD_XSTATS_HW_S_INFO = 0x2
IFLA_OFFLOAD_XSTATS_L3_STATS = 0x3
IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC = 0x0
IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST = 0x1
IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED = 0x2
IFLA_XDP_UNSPEC = 0x0
IFLA_XDP_FD = 0x1
IFLA_XDP_ATTACHED = 0x2
@@ -1940,11 +1885,6 @@ const (
IFLA_RMNET_UNSPEC = 0x0
IFLA_RMNET_MUX_ID = 0x1
IFLA_RMNET_FLAGS = 0x2
IFLA_MCTP_UNSPEC = 0x0
IFLA_MCTP_NET = 0x1
IFLA_DSA_UNSPEC = 0x0
IFLA_DSA_CONDUIT = 0x1
IFLA_DSA_MASTER = 0x1
)
const (
+4 -4
View File
@@ -40,7 +40,7 @@ github.com/fsmiamoto/git-todo-parser/todo
# github.com/gdamore/encoding v1.0.0
## explicit; go 1.9
github.com/gdamore/encoding
# github.com/gdamore/tcell/v2 v2.7.4
# github.com/gdamore/tcell/v2 v2.7.3
## explicit; go 1.12
github.com/gdamore/tcell/v2
github.com/gdamore/tcell/v2/terminfo
@@ -172,7 +172,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.20240309085756-86e0d5a312de
# github.com/jesseduffield/gocui v0.3.1-0.20240303173746-f2b0f1f68dd8
## explicit; go 1.12
github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
@@ -313,13 +313,13 @@ golang.org/x/exp/slices
golang.org/x/net/context
golang.org/x/net/internal/socks
golang.org/x/net/proxy
# golang.org/x/sys v0.18.0
# golang.org/x/sys v0.17.0
## explicit; go 1.18
golang.org/x/sys/cpu
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
# golang.org/x/term v0.18.0
# golang.org/x/term v0.17.0
## explicit; go 1.18
golang.org/x/term
# golang.org/x/text v0.14.0