mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-11 12:25:47 +02:00
Auto-wrap commit message while typing (#3173)
- **PR Description** Add new config settings `git.commit.autoWrapCommitMessage` (default true) and `git.commit.autoWrapWidth` (default 72), which allow automatic as-you-type wrapping of the commit message body to the specified width. There are occasional situations where this wrapping is in the way, for example when you need to have longer lines in the message for some reason (perhaps because you have a very wide ASCII art picture or table), and you'll have to resort to switching to the editor in that case. However, in my experience these cases are quite rare.
This commit is contained in:
commit
ac4767bb2a
24 changed files with 538 additions and 55 deletions
|
@ -92,6 +92,8 @@ 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
|
||||
|
|
8
go.mod
8
go.mod
|
@ -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.3
|
||||
github.com/gdamore/tcell/v2 v2.7.4
|
||||
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.20240303173746-f2b0f1f68dd8
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20240309085756-86e0d5a312de
|
||||
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.17.0 // indirect
|
||||
golang.org/x/term v0.17.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/term v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
|
14
go.sum
14
go.sum
|
@ -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.3 h1:YLQlOj5F0hSlKy5TJvlych29+WTcJzbElnLYwx8gvdg=
|
||||
github.com/gdamore/tcell/v2 v2.7.3/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
|
||||
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/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.20240303173746-f2b0f1f68dd8 h1:DGyAjpaAnxDuKO4MEoFjifhkUV7sU6znMR9eRfjjvn0=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20240303173746-f2b0f1f68dd8/go.mod h1:lLLfxEGyIvvkzzpHdKkfgIVFmxqEejeACxKMVxSHLeM=
|
||||
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/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,13 +470,15 @@ 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=
|
||||
|
|
|
@ -142,7 +142,7 @@ func (self *CommitCommands) GetCommitMessage(commitSha string) (string, error) {
|
|||
ToArgv()
|
||||
|
||||
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||
return strings.TrimSpace(message), err
|
||||
return strings.ReplaceAll(strings.TrimSpace(message), "\r\n", "\n"), err
|
||||
}
|
||||
|
||||
func (self *CommitCommands) GetCommitSubject(commitSha string) (string, error) {
|
||||
|
|
|
@ -236,6 +236,10 @@ 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 {
|
||||
|
@ -658,7 +662,9 @@ func GetDefaultConfig() *UserConfig {
|
|||
ExternalDiffCommand: "",
|
||||
},
|
||||
Commit: CommitConfig{
|
||||
SignOff: false,
|
||||
SignOff: false,
|
||||
AutoWrapCommitMessage: true,
|
||||
AutoWrapWidth: 72,
|
||||
},
|
||||
Merging: MergingConfig{
|
||||
ManualCommit: false,
|
||||
|
|
|
@ -38,10 +38,14 @@ 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,
|
||||
)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ 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"
|
||||
)
|
||||
|
||||
|
@ -100,7 +101,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.JoinCommitMessageAndDescription())
|
||||
self.context().SetHistoryMessage(self.c.Helpers().Commits.JoinCommitMessageAndUnwrappedDescription())
|
||||
}
|
||||
|
||||
validCommit, err := self.setCommitMessageAtIndex(newIndex)
|
||||
|
@ -119,6 +120,9 @@ 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
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
@ -16,10 +17,11 @@ type ICommitsHelper interface {
|
|||
type CommitsHelper struct {
|
||||
c *HelperCommon
|
||||
|
||||
getCommitSummary func() string
|
||||
setCommitSummary func(string)
|
||||
getCommitDescription func() string
|
||||
setCommitDescription func(string)
|
||||
getCommitSummary func() string
|
||||
setCommitSummary func(string)
|
||||
getCommitDescription func() string
|
||||
getUnwrappedCommitDescription func() string
|
||||
setCommitDescription func(string)
|
||||
}
|
||||
|
||||
var _ ICommitsHelper = &CommitsHelper{}
|
||||
|
@ -29,14 +31,16 @@ 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,
|
||||
setCommitDescription: setCommitDescription,
|
||||
c: c,
|
||||
getCommitSummary: getCommitSummary,
|
||||
setCommitSummary: setCommitSummary,
|
||||
getCommitDescription: getCommitDescription,
|
||||
getUnwrappedCommitDescription: getUnwrappedCommitDescription,
|
||||
setCommitDescription: setCommitDescription,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,11 +57,36 @@ func (self *CommitsHelper) SetMessageAndDescriptionInView(message string) {
|
|||
self.c.Contexts().CommitMessage.RenderCommitLength()
|
||||
}
|
||||
|
||||
func (self *CommitsHelper) JoinCommitMessageAndDescription() string {
|
||||
if len(self.getCommitDescription()) == 0 {
|
||||
func (self *CommitsHelper) JoinCommitMessageAndUnwrappedDescription() string {
|
||||
if len(self.getUnwrappedCommitDescription()) == 0 {
|
||||
return self.getCommitSummary()
|
||||
}
|
||||
return self.getCommitSummary() + "\n" + self.getCommitDescription()
|
||||
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)
|
||||
}
|
||||
|
||||
func (self *CommitsHelper) SwitchToEditor() error {
|
||||
|
@ -154,7 +183,7 @@ func (self *CommitsHelper) HandleCommitConfirm() error {
|
|||
|
||||
func (self *CommitsHelper) CloseCommitMessagePanel() error {
|
||||
if self.c.Contexts().CommitMessage.GetPreserveMessage() {
|
||||
message := self.JoinCommitMessageAndDescription()
|
||||
message := self.JoinCommitMessageAndUnwrappedDescription()
|
||||
|
||||
self.c.Contexts().CommitMessage.SetPreservedMessage(message)
|
||||
} else {
|
||||
|
|
41
pkg/gui/controllers/helpers/commits_helper_test.go
Normal file
41
pkg/gui/controllers/helpers/commits_helper_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -354,7 +354,9 @@ 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(),
|
||||
|
|
|
@ -168,6 +168,8 @@ 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)
|
||||
|
|
|
@ -31,6 +31,16 @@ 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)
|
||||
|
||||
|
|
59
pkg/integration/tests/commit/auto_wrap_message.go
Normal file
59
pkg/integration/tests/commit/auto_wrap_message.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
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."))
|
||||
},
|
||||
})
|
|
@ -65,6 +65,7 @@ var tests = []*components.IntegrationTest{
|
|||
cherry_pick.CherryPickRange,
|
||||
commit.AddCoAuthor,
|
||||
commit.Amend,
|
||||
commit.AutoWrapMessage,
|
||||
commit.Commit,
|
||||
commit.CommitMultiline,
|
||||
commit.CommitSwitchToEditor,
|
||||
|
|
|
@ -405,6 +405,16 @@
|
|||
"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,
|
||||
|
|
6
vendor/github.com/gdamore/tcell/v2/console_win.go
generated
vendored
6
vendor/github.com/gdamore/tcell/v2/console_win.go
generated
vendored
|
@ -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)))
|
||||
|
|
168
vendor/github.com/jesseduffield/gocui/text_area.go
generated
vendored
168
vendor/github.com/jesseduffield/gocui/text_area.go
generated
vendored
|
@ -11,11 +11,59 @@ const (
|
|||
WORD_SEPARATORS = "*?_+-.[]~=/&;!#$%^(){}<>"
|
||||
)
|
||||
|
||||
type CursorMapping struct {
|
||||
Orig int
|
||||
Wrapped int
|
||||
}
|
||||
|
||||
type TextArea struct {
|
||||
content []rune
|
||||
cursor int
|
||||
overwrite bool
|
||||
clipboard string
|
||||
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{}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *TextArea) TypeRune(r rune) {
|
||||
|
@ -27,6 +75,7 @@ func (self *TextArea) TypeRune(r rune) {
|
|||
append([]rune{r}, self.content[self.cursor:]...)...,
|
||||
)
|
||||
}
|
||||
self.autoWrapContent()
|
||||
|
||||
self.cursor++
|
||||
}
|
||||
|
@ -37,6 +86,7 @@ func (self *TextArea) BackSpaceChar() {
|
|||
}
|
||||
|
||||
self.content = append(self.content[:self.cursor-1], self.content[self.cursor:]...)
|
||||
self.autoWrapContent()
|
||||
self.cursor--
|
||||
}
|
||||
|
||||
|
@ -46,6 +96,7 @@ func (self *TextArea) DeleteChar() {
|
|||
}
|
||||
|
||||
self.content = append(self.content[:self.cursor], self.content[self.cursor+1:]...)
|
||||
self.autoWrapContent()
|
||||
}
|
||||
|
||||
func (self *TextArea) MoveCursorLeft() {
|
||||
|
@ -123,6 +174,10 @@ func (self *TextArea) MoveCursorDown() {
|
|||
}
|
||||
|
||||
func (self *TextArea) GetContent() string {
|
||||
return string(self.wrappedContent)
|
||||
}
|
||||
|
||||
func (self *TextArea) GetUnwrappedContent() string {
|
||||
return string(self.content)
|
||||
}
|
||||
|
||||
|
@ -144,14 +199,24 @@ 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
|
||||
}
|
||||
|
||||
|
@ -159,18 +224,30 @@ 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.atLineStart() {
|
||||
if self.atSoftLineStart() {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -181,15 +258,21 @@ func (self *TextArea) GoToStartOfLine() {
|
|||
}
|
||||
|
||||
func (self *TextArea) closestNewlineOnLeft() int {
|
||||
wrappedCursor := self.origCursorToWrappedCursor(self.cursor)
|
||||
|
||||
newlineIndex := -1
|
||||
|
||||
for i, r := range self.content[0:self.cursor] {
|
||||
for i, r := range self.wrappedContent[0:wrappedCursor] {
|
||||
if r == '\n' {
|
||||
newlineIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
return newlineIndex
|
||||
unwrappedNewlineIndex := self.wrappedCursorToOrigCursor(newlineIndex)
|
||||
if unwrappedNewlineIndex >= 0 && self.content[unwrappedNewlineIndex] != '\n' {
|
||||
unwrappedNewlineIndex--
|
||||
}
|
||||
return unwrappedNewlineIndex
|
||||
}
|
||||
|
||||
func (self *TextArea) GoToEndOfLine() {
|
||||
|
@ -198,12 +281,22 @@ 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 {
|
||||
for i, r := range self.content[self.cursor:] {
|
||||
wrappedCursor := self.origCursorToWrappedCursor(self.cursor)
|
||||
|
||||
for i, r := range self.wrappedContent[wrappedCursor:] {
|
||||
if r == '\n' {
|
||||
return self.cursor + i
|
||||
return self.wrappedCursorToOrigCursor(wrappedCursor + i)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,11 +308,23 @@ 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
|
||||
|
@ -246,16 +351,50 @@ 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
|
||||
for _, r := range self.content[0:self.cursor] {
|
||||
wrappedCursor := self.origCursorToWrappedCursor(self.cursor)
|
||||
for _, r := range self.wrappedContent[0:wrappedCursor] {
|
||||
if r == '\n' {
|
||||
cursorY++
|
||||
cursorX = 0
|
||||
|
@ -278,15 +417,15 @@ func (self *TextArea) SetCursor2D(x int, y int) {
|
|||
}
|
||||
|
||||
newCursor := 0
|
||||
for _, r := range self.content {
|
||||
for _, r := range self.wrappedContent {
|
||||
if x <= 0 && y == 0 {
|
||||
self.cursor = newCursor
|
||||
self.cursor = self.wrappedCursorToOrigCursor(newCursor)
|
||||
return
|
||||
}
|
||||
|
||||
if r == '\n' {
|
||||
if y == 0 {
|
||||
self.cursor = newCursor
|
||||
self.cursor = self.wrappedCursorToOrigCursor(newCursor)
|
||||
return
|
||||
}
|
||||
y--
|
||||
|
@ -304,11 +443,12 @@ func (self *TextArea) SetCursor2D(x int, y int) {
|
|||
return
|
||||
}
|
||||
|
||||
self.cursor = newCursor
|
||||
self.cursor = self.wrappedCursorToOrigCursor(newCursor)
|
||||
}
|
||||
|
||||
func (self *TextArea) Clear() {
|
||||
self.content = []rune{}
|
||||
self.wrappedContent = []rune{}
|
||||
self.cursor = 0
|
||||
}
|
||||
|
||||
|
|
2
vendor/golang.org/x/sys/unix/aliases.go
generated
vendored
2
vendor/golang.org/x/sys/unix/aliases.go
generated
vendored
|
@ -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) && go1.9
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
|
||||
package unix
|
||||
|
||||
|
|
2
vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
generated
vendored
2
vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
generated
vendored
|
@ -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 && go1.12
|
||||
//go:build darwin
|
||||
|
||||
package unix
|
||||
|
||||
|
|
12
vendor/golang.org/x/sys/unix/syscall_freebsd.go
generated
vendored
12
vendor/golang.org/x/sys/unix/syscall_freebsd.go
generated
vendored
|
@ -13,6 +13,7 @@
|
|||
package unix
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
@ -169,25 +170,26 @@ 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)
|
||||
if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil {
|
||||
// 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) {
|
||||
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 {
|
||||
if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
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 {
|
||||
if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
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 {
|
||||
if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -205,7 +207,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 {
|
||||
if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
99
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
99
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
|
@ -1849,6 +1849,105 @@ 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
vendor/golang.org/x/sys/unix/zsyscall_linux.go
generated
vendored
10
vendor/golang.org/x/sys/unix/zsyscall_linux.go
generated
vendored
|
@ -906,6 +906,16 @@ 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
vendor/golang.org/x/sys/unix/ztypes_linux.go
generated
vendored
60
vendor/golang.org/x/sys/unix/ztypes_linux.go
generated
vendored
|
@ -836,6 +836,15 @@ 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 {
|
||||
|
@ -1550,6 +1559,7 @@ 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
|
||||
|
@ -1565,6 +1575,7 @@ 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
|
||||
|
@ -1612,6 +1623,9 @@ 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
|
||||
|
@ -1649,6 +1663,14 @@ 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
|
||||
|
@ -1670,6 +1692,9 @@ 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
|
||||
|
@ -1693,9 +1718,22 @@ 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
|
||||
|
@ -1726,6 +1764,8 @@ 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
|
||||
|
@ -1740,6 +1780,7 @@ 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
|
||||
|
@ -1752,6 +1793,8 @@ 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
|
||||
|
@ -1781,6 +1824,9 @@ 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
|
||||
|
@ -1796,6 +1842,7 @@ 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
|
||||
|
@ -1854,8 +1901,16 @@ 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
|
||||
|
@ -1885,6 +1940,11 @@ 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 (
|
||||
|
|
8
vendor/modules.txt
vendored
8
vendor/modules.txt
vendored
|
@ -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.3
|
||||
# github.com/gdamore/tcell/v2 v2.7.4
|
||||
## 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.20240303173746-f2b0f1f68dd8
|
||||
# github.com/jesseduffield/gocui v0.3.1-0.20240309085756-86e0d5a312de
|
||||
## 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.17.0
|
||||
# golang.org/x/sys v0.18.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.17.0
|
||||
# golang.org/x/term v0.18.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/term
|
||||
# golang.org/x/text v0.14.0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue