diff --git a/go.mod b/go.mod index 0b4536e29..b676e4938 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( 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.20241223111608-9967d0e928a0 + github.com/jesseduffield/gocui v0.3.1-0.20250106080306-164661a92088 github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e @@ -75,8 +75,8 @@ require ( github.com/xanzy/ssh-agent v0.2.1 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index 17a4b9ccb..dcb1b0bda 100644 --- a/go.sum +++ b/go.sum @@ -188,8 +188,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.20241223111608-9967d0e928a0 h1:R29+E15wHqTDBfZxmzCLu0x34j5ljsXWT/DhR+2YiOU= -github.com/jesseduffield/gocui v0.3.1-0.20241223111608-9967d0e928a0/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8= +github.com/jesseduffield/gocui v0.3.1-0.20250106080306-164661a92088 h1:yAJ+yFWcv1WRsbgoc4BrGxZVqdLiGVMkz+hEQ1ktgb0= +github.com/jesseduffield/gocui v0.3.1-0.20250106080306-164661a92088/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8= github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g= github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a/go.mod h1:FSWDLKT0NQpntbDd1H3lbz51fhCVlMzy/J0S6nM727Q= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY= @@ -476,14 +476,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc 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/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.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/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= 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= diff --git a/pkg/integration/tests/patch_building/move_to_index_part_of_adjacent_added_lines.go b/pkg/integration/tests/patch_building/move_to_index_part_of_adjacent_added_lines.go index 89d8c366a..bf06270b7 100644 --- a/pkg/integration/tests/patch_building/move_to_index_part_of_adjacent_added_lines.go +++ b/pkg/integration/tests/patch_building/move_to_index_part_of_adjacent_added_lines.go @@ -64,6 +64,6 @@ var MoveToIndexPartOfAdjacentAddedLines = NewIntegrationTest(NewIntegrationTestA ) t.Views().Main(). - Content(Contains("+1st line\n 2nd line\n")) + Content(Contains("+1st line\n 2nd line")) }, }) diff --git a/pkg/integration/tests/stash/stash_staged_partial_file.go b/pkg/integration/tests/stash/stash_staged_partial_file.go index d9ac30e1b..8219b55d3 100644 --- a/pkg/integration/tests/stash/stash_staged_partial_file.go +++ b/pkg/integration/tests/stash/stash_staged_partial_file.go @@ -23,12 +23,12 @@ var StashStagedPartialFile = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Staging(). Content( - Contains(" line1\n-line2\n+line2 mod\n line3\n-line4\n+line4 mod\n"), + Contains(" line1\n-line2\n+line2 mod\n line3\n-line4\n+line4 mod"), ). PressPrimaryAction(). PressPrimaryAction(). Content( - Contains(" line1\n line2 mod\n line3\n-line4\n+line4 mod\n"), + Contains(" line1\n line2 mod\n line3\n-line4\n+line4 mod"), ). PressEscape() @@ -54,7 +54,7 @@ var StashStagedPartialFile = NewIntegrationTest(NewIntegrationTestArgs{ ) t.Views().Main(). Content( - Contains(" line1\n-line2\n+line2 mod\n line3\n line4\n"), + Contains(" line1\n-line2\n+line2 mod\n line3\n line4"), ) t.Views().Files(). @@ -64,7 +64,7 @@ var StashStagedPartialFile = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Staging(). Content( - Contains(" line1\n line2\n line3\n-line4\n+line4 mod\n"), + Contains(" line1\n line2\n line3\n-line4\n+line4 mod"), ) }, }) diff --git a/pkg/utils/lines.go b/pkg/utils/lines.go index 197b77975..d2ce7fdc6 100644 --- a/pkg/utils/lines.go +++ b/pkg/utils/lines.go @@ -110,6 +110,7 @@ func ScanLinesAndTruncateWhenLongerThanBuffer(maxBufferSize int) func(data []byt // If wrap is false, the text is returned as is. // This code needs to behave the same as `gocui.lineWrap` does. func WrapViewLinesToWidth(wrap bool, text string, width int) ([]string, []int, []int) { + text = strings.TrimSuffix(text, "\n") lines := strings.Split(text, "\n") if !wrap { indices := make([]int, len(lines)) diff --git a/pkg/utils/lines_test.go b/pkg/utils/lines_test.go index 5fc6a07b0..c2b90356f 100644 --- a/pkg/utils/lines_test.go +++ b/pkg/utils/lines_test.go @@ -374,10 +374,9 @@ func TestWrapViewLinesToWidth(t *testing.T) { "longer.", "Third", "paragraph", - "", }, - expectedWrappedLinesIndices: []int{0, 2, 6, 8}, - expectedOriginalLinesIndices: []int{0, 0, 1, 1, 1, 1, 2, 2, 3}, + expectedWrappedLinesIndices: []int{0, 2, 6}, + expectedOriginalLinesIndices: []int{0, 0, 1, 1, 1, 1, 2, 2}, }, } for _, tt := range tests { diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go index 5a331b43e..0a54c51c1 100644 --- a/vendor/github.com/jesseduffield/gocui/view.go +++ b/vendor/github.com/jesseduffield/gocui/view.go @@ -66,6 +66,11 @@ type View struct { // true and viewLines to nil viewLines []viewLine + // If the last character written was a newline, we don't write it but + // instead set pendingNewline to true. If more text is written, we write the + // newline then. This is to avoid having an extra blank at the end of the view. + pendingNewline bool + // writeMutex protects locks the write process writeMutex sync.Mutex @@ -647,6 +652,9 @@ func (v *View) SetWritePos(x, y int) { v.wx = x v.wy = y + + // Changing the write position makes a pending newline obsolete + v.pendingNewline = false } // WritePos returns the current write position of the view's internal buffer. @@ -690,7 +698,7 @@ func (v *View) makeWriteable(x, y int) { v.lines = append(v.lines, nil) } } - // cell `x` must not be index-able (that's why `<`) + // cell `x` need not be index-able (that's why `<`) // append should be used by `lines[y]` user if he wants to write beyond `x` for len(v.lines[y]) < x { if cap(v.lines[y]) > len(v.lines[y]) { @@ -726,14 +734,6 @@ func (v *View) writeCells(x, y int, cells []cell) { v.lines[y] = line[:newLen] } -// readCell gets cell at specified location (x, y) -func (v *View) readCell(x, y int) (cell, bool) { - if y < 0 || y >= len(v.lines) || x < 0 || x >= len(v.lines[y]) { - return cell{}, false - } - return v.lines[y][x], true -} - // Write appends a byte slice into the view's internal buffer. Because // View implements the io.Writer interface, it can be passed as parameter // of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must @@ -762,31 +762,43 @@ func (v *View) writeRunes(p []rune) { // Fill with empty cells, if writing outside current view buffer v.makeWriteable(v.wx, v.wy) - for _, r := range p { + finishLine := func() { + v.autoRenderHyperlinksInCurrentLine() + if v.wx >= len(v.lines[v.wy]) { + v.writeCells(v.wx, v.wy, []cell{{ + chr: 0, + fgColor: 0, + bgColor: 0, + }}) + } + } + + advanceToNextLine := func() { + v.wx = 0 + v.wy++ + if v.wy >= len(v.lines) { + v.lines = append(v.lines, nil) + } + } + + if v.pendingNewline { + advanceToNextLine() + v.pendingNewline = false + } + + until := len(p) + if until > 0 && p[until-1] == '\n' { + v.pendingNewline = true + until-- + } + + for _, r := range p[:until] { switch r { case '\n': - v.autoRenderHyperlinksInCurrentLine() - if c, ok := v.readCell(v.wx+1, v.wy); !ok || c.chr == 0 { - v.writeCells(v.wx, v.wy, []cell{{ - chr: 0, - fgColor: 0, - bgColor: 0, - }}) - } - v.wx = 0 - v.wy++ - if v.wy >= len(v.lines) { - v.lines = append(v.lines, nil) - } + finishLine() + advanceToNextLine() case '\r': - v.autoRenderHyperlinksInCurrentLine() - if c, ok := v.readCell(v.wx, v.wy); !ok || c.chr == 0 { - v.writeCells(v.wx, v.wy, []cell{{ - chr: 0, - fgColor: 0, - bgColor: 0, - }}) - } + finishLine() v.wx = 0 default: truncateLine, cells := v.parseInput(r, v.wx, v.wy) @@ -803,6 +815,10 @@ func (v *View) writeRunes(p []rune) { } } + if v.pendingNewline { + finishLine() + } + v.updateSearchPositions() } diff --git a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go index 97cb916f2..be8c00207 100644 --- a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go +++ b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go @@ -246,6 +246,18 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e return sendfile(outfd, infd, offset, count) } +func Dup3(oldfd, newfd, flags int) error { + if oldfd == newfd || flags&^O_CLOEXEC != 0 { + return EINVAL + } + how := F_DUP2FD + if flags&O_CLOEXEC != 0 { + how = F_DUP2FD_CLOEXEC + } + _, err := fcntl(oldfd, how, newfd) + return err +} + /* * Exposed directly */ diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go index 4e613cf63..3ca814f54 100644 --- a/vendor/golang.org/x/sys/windows/dll_windows.go +++ b/vendor/golang.org/x/sys/windows/dll_windows.go @@ -43,8 +43,8 @@ type DLL struct { // LoadDLL loads DLL file into memory. // // Warning: using LoadDLL without an absolute path name is subject to -// DLL preloading attacks. To safely load a system DLL, use LazyDLL -// with System set to true, or use LoadLibraryEx directly. +// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL], +// or use [LoadLibraryEx] directly. func LoadDLL(name string) (dll *DLL, err error) { namep, err := UTF16PtrFromString(name) if err != nil { @@ -271,6 +271,9 @@ func (d *LazyDLL) NewProc(name string) *LazyProc { } // NewLazyDLL creates new LazyDLL associated with DLL file. +// +// Warning: using NewLazyDLL without an absolute path name is subject to +// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL]. func NewLazyDLL(name string) *LazyDLL { return &LazyDLL{Name: name} } @@ -410,7 +413,3 @@ func loadLibraryEx(name string, system bool) (*DLL, error) { } return &DLL{Name: name, Handle: h}, nil } - -type errString string - -func (s errString) Error() string { return string(s) } diff --git a/vendor/modules.txt b/vendor/modules.txt index ff2ed53ff..3deabb0ce 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -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.20241223111608-9967d0e928a0 +# github.com/jesseduffield/gocui v0.3.1-0.20250106080306-164661a92088 ## explicit; go 1.12 github.com/jesseduffield/gocui # github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a @@ -314,13 +314,13 @@ golang.org/x/net/proxy # golang.org/x/sync v0.10.0 ## explicit; go 1.18 golang.org/x/sync/errgroup -# golang.org/x/sys v0.28.0 +# golang.org/x/sys v0.29.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.27.0 +# golang.org/x/term v0.28.0 ## explicit; go 1.18 golang.org/x/term # golang.org/x/text v0.21.0