mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-31 03:11:14 +02:00
reduce flicker without worrying about carriage returns
This commit is contained in:
parent
d5504fa5d0
commit
93fac1f312
4
go.mod
4
go.mod
@ -20,7 +20,7 @@ require (
|
||||
github.com/imdario/mergo v0.3.11
|
||||
github.com/integrii/flaggy v1.4.0
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210405093708-e79dab8f7772
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210409121040-210802112d8a
|
||||
github.com/jesseduffield/termbox-go v0.0.0-20200823212418-a2289ed6aafe // indirect
|
||||
github.com/jesseduffield/yaml v2.1.0+incompatible
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||
@ -40,7 +40,7 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
|
||||
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
||||
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 // indirect
|
||||
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
)
|
||||
|
||||
|
8
go.sum
8
go.sum
@ -102,6 +102,12 @@ github.com/jesseduffield/gocui v0.3.1-0.20210405041826-439abd8b6e07 h1:BymGR28au
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210405041826-439abd8b6e07/go.mod h1:QWq79xplEoyhQO+dgpk3sojjTVRKjQklyTlzm5nC5Kg=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210405093708-e79dab8f7772 h1:dg9krj10Udac4IcvlVCOAPktQkfggkgtqRmbDKk7Pzw=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210405093708-e79dab8f7772/go.mod h1:QWq79xplEoyhQO+dgpk3sojjTVRKjQklyTlzm5nC5Kg=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210406065811-95ef6e13779b h1:3+4+muhhikpls5FePXSRNFgcdoPx8dTdqaCy3AqLz98=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210406065811-95ef6e13779b/go.mod h1:QWq79xplEoyhQO+dgpk3sojjTVRKjQklyTlzm5nC5Kg=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210406065942-1b0c68414064 h1:Oe+QJuUIOd2TU+A3BW5sT1eXqceoBcOOfyoHlGf7F8Y=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210406065942-1b0c68414064/go.mod h1:QWq79xplEoyhQO+dgpk3sojjTVRKjQklyTlzm5nC5Kg=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210409121040-210802112d8a h1:ocrSuZxQIgWWt27b+rjiyIIPz6fzfFeoL5Q4cpa2cAo=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20210409121040-210802112d8a/go.mod h1:QWq79xplEoyhQO+dgpk3sojjTVRKjQklyTlzm5nC5Kg=
|
||||
github.com/jesseduffield/termbox-go v0.0.0-20200823212418-a2289ed6aafe h1:qsVhCf2RFyyKIUe/+gJblbCpXMUki9rZrHuEctg6M/E=
|
||||
github.com/jesseduffield/termbox-go v0.0.0-20200823212418-a2289ed6aafe/go.mod h1:anMibpZtqNxjDbxrcDEAwSdaJ37vyUeM1f/M4uekib4=
|
||||
github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE=
|
||||
@ -226,6 +232,8 @@ golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlp
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 h1:EC6+IGYTjPpRfv9a2b/6Puw0W+hLtAhkV1tPsXhutqs=
|
||||
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 h1:VqE9gduFZ4dbR7XoL77lHFp0/DyDUBKSXK7CMFkVcV0=
|
||||
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -83,13 +83,23 @@ func (gui *Gui) getManager(view *gocui.View) *tasks.ViewBufferManager {
|
||||
gui.Log,
|
||||
view,
|
||||
func() {
|
||||
view.Clear()
|
||||
// we could clear here, but that actually has the effect of causing a flicker
|
||||
// where the view may contain no content momentarily as the gui refreshes.
|
||||
// Instead, we're rewinding the write pointer so that we will just start
|
||||
// overwriting the existing content from the top down. Once we've reached
|
||||
// the end of the content do display, we call view.FlushStaleCells() to
|
||||
// clear out the remaining content from the previous render.
|
||||
view.Reset()
|
||||
},
|
||||
func() {
|
||||
gui.g.Update(func(*gocui.Gui) error {
|
||||
return nil
|
||||
})
|
||||
})
|
||||
},
|
||||
func() {
|
||||
view.FlushStaleCells()
|
||||
},
|
||||
)
|
||||
gui.viewBufferManagerMap[view.Name()] = manager
|
||||
}
|
||||
|
||||
|
@ -33,12 +33,13 @@ type ViewBufferManager struct {
|
||||
readLines chan int
|
||||
|
||||
// beforeStart is the function that is called before starting a new task
|
||||
beforeStart func()
|
||||
refreshView func()
|
||||
beforeStart func()
|
||||
refreshView func()
|
||||
flushStaleCells func()
|
||||
}
|
||||
|
||||
func NewViewBufferManager(log *logrus.Entry, writer io.Writer, beforeStart func(), refreshView func()) *ViewBufferManager {
|
||||
return &ViewBufferManager{Log: log, writer: writer, beforeStart: beforeStart, refreshView: refreshView, readLines: make(chan int, 1024)}
|
||||
func NewViewBufferManager(log *logrus.Entry, writer io.Writer, beforeStart func(), refreshView func(), flushStaleCells func()) *ViewBufferManager {
|
||||
return &ViewBufferManager{Log: log, writer: writer, beforeStart: beforeStart, refreshView: refreshView, flushStaleCells: flushStaleCells, readLines: make(chan int, 1024)}
|
||||
}
|
||||
|
||||
func (m *ViewBufferManager) ReadLines(n int) {
|
||||
@ -75,7 +76,7 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string
|
||||
loaded := false
|
||||
|
||||
go utils.Safe(func() {
|
||||
ticker := time.NewTicker(time.Millisecond * 100)
|
||||
ticker := time.NewTicker(time.Millisecond * 200)
|
||||
defer ticker.Stop()
|
||||
select {
|
||||
case <-ticker.C:
|
||||
@ -114,6 +115,9 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string
|
||||
default:
|
||||
}
|
||||
if !ok {
|
||||
// if we're here then there's nothing left to scan from the source
|
||||
// so we're at the EOF and can flush the stale content
|
||||
m.flushStaleCells()
|
||||
m.refreshView()
|
||||
break outer
|
||||
}
|
||||
|
5
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
5
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
@ -266,11 +266,14 @@ func (g *Gui) SetView(name string, x0, y0, x1, y1 int, overlaps byte) (*View, er
|
||||
}
|
||||
|
||||
if v, err := g.View(name); err == nil {
|
||||
if v.x0 != x0 || v.x1 != x1 || v.y0 != y0 || v.y1 != y1 {
|
||||
v.tainted = true
|
||||
}
|
||||
|
||||
v.x0 = x0
|
||||
v.y0 = y0
|
||||
v.x1 = x1
|
||||
v.y1 = y1
|
||||
v.tainted = true
|
||||
return v, nil
|
||||
}
|
||||
|
||||
|
76
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
76
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -518,16 +518,20 @@ func (v *View) writeCells(x, y int, cells []cell) {
|
||||
// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
|
||||
// be called to clear the view's buffer.
|
||||
func (v *View) Write(p []byte) (n int, err error) {
|
||||
v.tainted = true
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.tainted = true
|
||||
v.makeWriteable(v.wx, v.wy)
|
||||
v.writeRunes(bytes.Runes(p))
|
||||
v.writeMutex.Unlock()
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (v *View) WriteRunes(p []rune) {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.tainted = true
|
||||
|
||||
// Fill with empty cells, if writing outside current view buffer
|
||||
@ -640,8 +644,53 @@ func (v *View) Read(p []byte) (n int, err error) {
|
||||
return offset, io.EOF
|
||||
}
|
||||
|
||||
// Clear empties the view's internal buffer.
|
||||
// And resets reading and writing offsets.
|
||||
func (v *View) Clear() {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.rewind()
|
||||
v.tainted = true
|
||||
v.lines = nil
|
||||
v.viewLines = nil
|
||||
v.clearRunes()
|
||||
}
|
||||
|
||||
// Rewind sets read and write pos to (0, 0).
|
||||
func (v *View) Rewind() {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.rewind()
|
||||
}
|
||||
|
||||
// similar to Rewind but clears lines. Also similar to Clear but doesn't reset
|
||||
// viewLines
|
||||
func (v *View) Reset() {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.rewind()
|
||||
v.lines = nil
|
||||
}
|
||||
|
||||
// This is for when we've done a restart for the sake of avoiding a flicker and
|
||||
// we've reached the end of the new content to display: we need to clear the remaining
|
||||
// content from the previous round. We do this by setting v.viewLines to nil so that
|
||||
// we just render the new content from v.lines directly
|
||||
func (v *View) FlushStaleCells() {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.rewind()
|
||||
v.tainted = true
|
||||
v.viewLines = nil
|
||||
}
|
||||
|
||||
func (v *View) rewind() {
|
||||
v.ei.reset()
|
||||
|
||||
if err := v.SetReadPos(0, 0); err != nil {
|
||||
// SetReadPos returns error only if x and y are negative
|
||||
// we are passing 0, 0, thus no error should occur.
|
||||
@ -718,7 +767,7 @@ func (v *View) draw() error {
|
||||
v.ox = 0
|
||||
}
|
||||
if v.tainted {
|
||||
v.viewLines = nil
|
||||
lineIdx := 0
|
||||
lines := v.lines
|
||||
if v.HasLoader {
|
||||
lines = v.loaderLines()
|
||||
@ -732,7 +781,13 @@ func (v *View) draw() error {
|
||||
ls := lineWrap(line, wrap)
|
||||
for j := range ls {
|
||||
vline := viewLine{linesX: j, linesY: i, line: ls[j]}
|
||||
v.viewLines = append(v.viewLines, vline)
|
||||
|
||||
if lineIdx > len(v.viewLines)-1 {
|
||||
v.viewLines = append(v.viewLines, vline)
|
||||
} else {
|
||||
v.viewLines[lineIdx] = vline
|
||||
}
|
||||
lineIdx++
|
||||
}
|
||||
}
|
||||
if !v.HasLoader {
|
||||
@ -828,19 +883,6 @@ func (v *View) realPosition(vx, vy int) (x, y int, err error) {
|
||||
return x, y, nil
|
||||
}
|
||||
|
||||
// Clear empties the view's internal buffer.
|
||||
// And resets reading and writing offsets.
|
||||
func (v *View) Clear() {
|
||||
v.writeMutex.Lock()
|
||||
v.Rewind()
|
||||
v.tainted = true
|
||||
v.ei.reset()
|
||||
v.lines = nil
|
||||
v.viewLines = nil
|
||||
v.clearRunes()
|
||||
v.writeMutex.Unlock()
|
||||
}
|
||||
|
||||
// clearRunes erases all the cells in the view.
|
||||
func (v *View) clearRunes() {
|
||||
maxX, maxY := v.Size()
|
||||
|
111
vendor/golang.org/x/term/term_solaris.go
generated
vendored
111
vendor/golang.org/x/term/term_solaris.go
generated
vendored
@ -1,111 +0,0 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package term
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// State contains the state of a terminal.
|
||||
type state struct {
|
||||
termios unix.Termios
|
||||
}
|
||||
|
||||
func isTerminal(fd int) bool {
|
||||
_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func readPassword(fd int) ([]byte, error) {
|
||||
// see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
|
||||
val, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oldState := *val
|
||||
|
||||
newState := oldState
|
||||
newState.Lflag &^= syscall.ECHO
|
||||
newState.Lflag |= syscall.ICANON | syscall.ISIG
|
||||
newState.Iflag |= syscall.ICRNL
|
||||
err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState)
|
||||
|
||||
var buf [16]byte
|
||||
var ret []byte
|
||||
for {
|
||||
n, err := syscall.Read(fd, buf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
if len(ret) == 0 {
|
||||
return nil, io.EOF
|
||||
}
|
||||
break
|
||||
}
|
||||
if buf[n-1] == '\n' {
|
||||
n--
|
||||
}
|
||||
ret = append(ret, buf[:n]...)
|
||||
if n < len(buf) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func makeRaw(fd int) (*State, error) {
|
||||
// see http://cr.illumos.org/~webrev/andy_js/1060/
|
||||
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldState := State{state{termios: *termios}}
|
||||
|
||||
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
||||
termios.Oflag &^= unix.OPOST
|
||||
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
||||
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
||||
termios.Cflag |= unix.CS8
|
||||
termios.Cc[unix.VMIN] = 1
|
||||
termios.Cc[unix.VTIME] = 0
|
||||
|
||||
if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oldState, nil
|
||||
}
|
||||
|
||||
func restore(fd int, oldState *State) error {
|
||||
return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
|
||||
}
|
||||
|
||||
func getState(fd int) (*State, error) {
|
||||
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &State{state{termios: *termios}}, nil
|
||||
}
|
||||
|
||||
func getSize(fd int) (width, height int, err error) {
|
||||
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return int(ws.Col), int(ws.Row), nil
|
||||
}
|
4
vendor/golang.org/x/term/term_unix.go
generated
vendored
4
vendor/golang.org/x/term/term_unix.go
generated
vendored
@ -2,8 +2,8 @@
|
||||
// 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 || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd zos
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package term
|
||||
|
||||
|
10
vendor/golang.org/x/term/term_unix_solaris.go
generated
vendored
Normal file
10
vendor/golang.org/x/term/term_unix_solaris.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package term
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TCGETS
|
||||
const ioctlWriteTermios = unix.TCSETS
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -149,7 +149,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.20210405093708-e79dab8f7772
|
||||
# github.com/jesseduffield/gocui v0.3.1-0.20210409121040-210802112d8a
|
||||
## explicit
|
||||
github.com/jesseduffield/gocui
|
||||
# github.com/jesseduffield/termbox-go v0.0.0-20200823212418-a2289ed6aafe
|
||||
@ -242,7 +242,7 @@ golang.org/x/sys/internal/unsafeheader
|
||||
golang.org/x/sys/plan9
|
||||
golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
# golang.org/x/term v0.0.0-20210317153231-de623e64d2a6
|
||||
# golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72
|
||||
## explicit
|
||||
golang.org/x/term
|
||||
# golang.org/x/text v0.3.6
|
||||
|
Loading…
Reference in New Issue
Block a user