mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-03 13:21:56 +02:00
add scrollbars
This commit is contained in:
parent
b838b74801
commit
e68093fe99
2
go.mod
2
go.mod
@ -16,7 +16,7 @@ require (
|
|||||||
github.com/integrii/flaggy v1.4.0
|
github.com/integrii/flaggy v1.4.0
|
||||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20220415005542-2eb424ce3d0a
|
github.com/jesseduffield/gocui v0.3.1-0.20220416053910-5b19e175bc67
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||||
github.com/jesseduffield/yaml v2.1.0+incompatible
|
github.com/jesseduffield/yaml v2.1.0+incompatible
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||||
|
4
go.sum
4
go.sum
@ -70,8 +70,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/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg=
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg=
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20220415005542-2eb424ce3d0a h1:Fd8B7eZJfwK0cFzqz2gEFLEDiY0iwJTm6oBbPRHONxA=
|
github.com/jesseduffield/gocui v0.3.1-0.20220416053910-5b19e175bc67 h1:6NIOoR4LMuNEkP6e9P6GVZkzgYZ7rqpfM+LieKqubnA=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20220415005542-2eb424ce3d0a/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
|
github.com/jesseduffield/gocui v0.3.1-0.20220416053910-5b19e175bc67/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
|
||||||
github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE=
|
github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE=
|
||||||
|
@ -3,7 +3,6 @@ package context
|
|||||||
import (
|
import (
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const HORIZONTAL_SCROLL_FACTOR = 3
|
const HORIZONTAL_SCROLL_FACTOR = 3
|
||||||
@ -43,20 +42,31 @@ func (self *ViewTrait) SetOriginX(value int) {
|
|||||||
_ = self.view.SetOriginX(value)
|
_ = self.view.SetOriginX(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tells us the bounds of line indexes shown in the view currently
|
// tells us the start of line indexes shown in the view currently as well as the capacity of lines shown in the viewport.
|
||||||
func (self *ViewTrait) ViewPortYBounds() (int, int) {
|
func (self *ViewTrait) ViewPortYBounds() (int, int) {
|
||||||
_, min := self.view.Origin()
|
_, start := self.view.Origin()
|
||||||
max := self.view.InnerHeight() + 1
|
length := self.view.InnerHeight() + 1
|
||||||
return min, max
|
return start, length
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ViewTrait) ScrollLeft() {
|
func (self *ViewTrait) ScrollLeft() {
|
||||||
newOriginX := utils.Max(self.view.OriginX()-self.view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR, 0)
|
self.view.ScrollLeft(self.horizontalScrollAmount())
|
||||||
_ = self.view.SetOriginX(newOriginX)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ViewTrait) ScrollRight() {
|
func (self *ViewTrait) ScrollRight() {
|
||||||
_ = self.view.SetOriginX(self.view.OriginX() + self.view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR)
|
self.view.ScrollRight(self.horizontalScrollAmount())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ViewTrait) horizontalScrollAmount() int {
|
||||||
|
return self.view.InnerWidth() / HORIZONTAL_SCROLL_FACTOR
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ViewTrait) ScrollUp() {
|
||||||
|
self.view.ScrollUp(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ViewTrait) ScrollDown() {
|
||||||
|
self.view.ScrollDown(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this returns the amount we'll scroll if we want to scroll by a page.
|
// this returns the amount we'll scroll if we want to scroll by a page.
|
||||||
|
@ -15,8 +15,8 @@ type ViewportListContextTrait struct {
|
|||||||
func (self *ViewportListContextTrait) FocusLine() {
|
func (self *ViewportListContextTrait) FocusLine() {
|
||||||
self.ListContextTrait.FocusLine()
|
self.ListContextTrait.FocusLine()
|
||||||
|
|
||||||
min, max := self.GetViewTrait().ViewPortYBounds()
|
startIdx, length := self.GetViewTrait().ViewPortYBounds()
|
||||||
displayStrings := self.ListContextTrait.getDisplayStrings(min, max)
|
displayStrings := self.ListContextTrait.getDisplayStrings(startIdx, length)
|
||||||
content := utils.RenderDisplayStrings(displayStrings)
|
content := utils.RenderDisplayStrings(displayStrings)
|
||||||
self.GetViewTrait().SetViewPortContent(content)
|
self.GetViewTrait().SetViewPortContent(content)
|
||||||
}
|
}
|
||||||
|
@ -43,14 +43,42 @@ func (self *ListController) HandleNextLine() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListController) HandleScrollLeft() error {
|
func (self *ListController) HandleScrollLeft() error {
|
||||||
return self.scroll(self.context.GetViewTrait().ScrollLeft)
|
return self.scrollHorizontal(self.context.GetViewTrait().ScrollLeft)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListController) HandleScrollRight() error {
|
func (self *ListController) HandleScrollRight() error {
|
||||||
return self.scroll(self.context.GetViewTrait().ScrollRight)
|
return self.scrollHorizontal(self.context.GetViewTrait().ScrollRight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListController) scroll(scrollFunc func()) error {
|
func (self *ListController) HandleScrollUp() error {
|
||||||
|
self.context.GetViewTrait().ScrollUp()
|
||||||
|
|
||||||
|
// we only need to do a line change if our line has been pushed out of the viewport, because
|
||||||
|
// at the moment much logic depends on the selected line always being visible
|
||||||
|
if !self.isSelectedLineInViewPort() {
|
||||||
|
return self.handleLineChange(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ListController) HandleScrollDown() error {
|
||||||
|
self.context.GetViewTrait().ScrollDown()
|
||||||
|
|
||||||
|
if !self.isSelectedLineInViewPort() {
|
||||||
|
return self.handleLineChange(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ListController) isSelectedLineInViewPort() bool {
|
||||||
|
selectedLineIdx := self.context.GetList().GetSelectedLineIdx()
|
||||||
|
startIdx, length := self.context.GetViewTrait().ViewPortYBounds()
|
||||||
|
return selectedLineIdx >= startIdx && selectedLineIdx < startIdx+length
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ListController) scrollHorizontal(scrollFunc func()) error {
|
||||||
scrollFunc()
|
scrollFunc()
|
||||||
|
|
||||||
return self.context.HandleFocus()
|
return self.context.HandleFocus()
|
||||||
@ -157,7 +185,7 @@ func (self *ListController) GetMouseKeybindings(opts types.KeybindingsOpts) []*g
|
|||||||
ViewName: self.context.GetViewName(),
|
ViewName: self.context.GetViewName(),
|
||||||
ToContext: string(self.context.GetKey()),
|
ToContext: string(self.context.GetKey()),
|
||||||
Key: gocui.MouseWheelUp,
|
Key: gocui.MouseWheelUp,
|
||||||
Handler: func(gocui.ViewMouseBindingOpts) error { return self.HandlePrevLine() },
|
Handler: func(gocui.ViewMouseBindingOpts) error { return self.HandleScrollUp() },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: self.context.GetViewName(),
|
ViewName: self.context.GetViewName(),
|
||||||
@ -169,7 +197,7 @@ func (self *ListController) GetMouseKeybindings(opts types.KeybindingsOpts) []*g
|
|||||||
ViewName: self.context.GetViewName(),
|
ViewName: self.context.GetViewName(),
|
||||||
ToContext: string(self.context.GetKey()),
|
ToContext: string(self.context.GetKey()),
|
||||||
Key: gocui.MouseWheelDown,
|
Key: gocui.MouseWheelDown,
|
||||||
Handler: func(gocui.ViewMouseBindingOpts) error { return self.HandleNextLine() },
|
Handler: func(gocui.ViewMouseBindingOpts) error { return self.HandleScrollDown() },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,15 +46,15 @@ func (gui *Gui) handleFocusCommandLog() error {
|
|||||||
func (gui *Gui) scrollUpExtra() error {
|
func (gui *Gui) scrollUpExtra() error {
|
||||||
gui.Views.Extras.Autoscroll = false
|
gui.Views.Extras.Autoscroll = false
|
||||||
|
|
||||||
return gui.scrollUpView(gui.Views.Extras)
|
gui.scrollUpView(gui.Views.Extras)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollDownExtra() error {
|
func (gui *Gui) scrollDownExtra() error {
|
||||||
gui.Views.Extras.Autoscroll = false
|
gui.Views.Extras.Autoscroll = false
|
||||||
|
|
||||||
if err := gui.scrollDownView(gui.Views.Extras); err != nil {
|
gui.scrollDownView(gui.Views.Extras)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package gui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
@ -63,56 +62,17 @@ func (gui *Gui) prevScreenMode() error {
|
|||||||
return gui.rerenderViewsWithScreenModeDependentContent()
|
return gui.rerenderViewsWithScreenModeDependentContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollUpView(view *gocui.View) error {
|
func (gui *Gui) scrollUpView(view *gocui.View) {
|
||||||
ox, oy := view.Origin()
|
view.ScrollUp(gui.c.UserConfig.Gui.ScrollHeight)
|
||||||
newOy := int(math.Max(0, float64(oy-gui.c.UserConfig.Gui.ScrollHeight)))
|
|
||||||
return view.SetOrigin(ox, newOy)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollDownView(view *gocui.View) error {
|
func (gui *Gui) scrollDownView(view *gocui.View) {
|
||||||
ox, oy := view.Origin()
|
scrollHeight := gui.c.UserConfig.Gui.ScrollHeight
|
||||||
scrollHeight := gui.linesToScrollDown(view)
|
view.ScrollDown(scrollHeight)
|
||||||
if scrollHeight > 0 {
|
|
||||||
if err := view.SetOrigin(ox, oy+scrollHeight); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if manager, ok := gui.viewBufferManagerMap[view.Name()]; ok {
|
if manager, ok := gui.viewBufferManagerMap[view.Name()]; ok {
|
||||||
manager.ReadLines(scrollHeight)
|
manager.ReadLines(scrollHeight)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) linesToScrollDown(view *gocui.View) int {
|
|
||||||
_, oy := view.Origin()
|
|
||||||
y := oy
|
|
||||||
canScrollPastBottom := gui.c.UserConfig.Gui.ScrollPastBottom
|
|
||||||
if !canScrollPastBottom {
|
|
||||||
_, sy := view.Size()
|
|
||||||
y += sy
|
|
||||||
}
|
|
||||||
scrollHeight := gui.c.UserConfig.Gui.ScrollHeight
|
|
||||||
scrollableLines := view.ViewLinesHeight() - y
|
|
||||||
if scrollableLines < 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// margin is about how many lines must still appear if you scroll
|
|
||||||
// all the way down. In practice every file ends in a newline so it will really
|
|
||||||
// just show a single line
|
|
||||||
margin := 1
|
|
||||||
if canScrollPastBottom {
|
|
||||||
margin = 2
|
|
||||||
}
|
|
||||||
if scrollableLines-margin < scrollHeight {
|
|
||||||
scrollHeight = scrollableLines - margin
|
|
||||||
}
|
|
||||||
if oy+scrollHeight < 0 {
|
|
||||||
return 0
|
|
||||||
} else {
|
|
||||||
return scrollHeight
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollUpMain() error {
|
func (gui *Gui) scrollUpMain() error {
|
||||||
@ -120,7 +80,9 @@ func (gui *Gui) scrollUpMain() error {
|
|||||||
gui.State.Panels.Merging.UserVerticalScrolling = true
|
gui.State.Panels.Merging.UserVerticalScrolling = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.scrollUpView(gui.Views.Main)
|
gui.scrollUpView(gui.Views.Main)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollDownMain() error {
|
func (gui *Gui) scrollDownMain() error {
|
||||||
@ -128,7 +90,9 @@ func (gui *Gui) scrollDownMain() error {
|
|||||||
gui.State.Panels.Merging.UserVerticalScrolling = true
|
gui.State.Panels.Merging.UserVerticalScrolling = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.scrollDownView(gui.Views.Main)
|
gui.scrollDownView(gui.Views.Main)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollLeftMain() error {
|
func (gui *Gui) scrollLeftMain() error {
|
||||||
@ -153,11 +117,15 @@ func (gui *Gui) scrollRight(view *gocui.View) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollUpSecondary() error {
|
func (gui *Gui) scrollUpSecondary() error {
|
||||||
return gui.scrollUpView(gui.Views.Secondary)
|
gui.scrollUpView(gui.Views.Secondary)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollDownSecondary() error {
|
func (gui *Gui) scrollDownSecondary() error {
|
||||||
return gui.scrollDownView(gui.Views.Secondary)
|
gui.scrollDownView(gui.Views.Secondary)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollUpConfirmationPanel() error {
|
func (gui *Gui) scrollUpConfirmationPanel() error {
|
||||||
@ -165,7 +133,9 @@ func (gui *Gui) scrollUpConfirmationPanel() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.scrollUpView(gui.Views.Confirmation)
|
gui.scrollUpView(gui.Views.Confirmation)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) scrollDownConfirmationPanel() error {
|
func (gui *Gui) scrollDownConfirmationPanel() error {
|
||||||
@ -173,7 +143,9 @@ func (gui *Gui) scrollDownConfirmationPanel() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.scrollDownView(gui.Views.Confirmation)
|
gui.scrollDownView(gui.Views.Confirmation)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleRefresh() error {
|
func (gui *Gui) handleRefresh() error {
|
||||||
|
@ -661,11 +661,13 @@ func (gui *Gui) createAllViews() error {
|
|||||||
gui.Views.Secondary.Wrap = true
|
gui.Views.Secondary.Wrap = true
|
||||||
gui.Views.Secondary.FgColor = theme.GocuiDefaultTextColor
|
gui.Views.Secondary.FgColor = theme.GocuiDefaultTextColor
|
||||||
gui.Views.Secondary.IgnoreCarriageReturns = true
|
gui.Views.Secondary.IgnoreCarriageReturns = true
|
||||||
|
gui.Views.Secondary.CanScrollPastBottom = gui.c.UserConfig.Gui.ScrollPastBottom
|
||||||
|
|
||||||
gui.Views.Main.Title = gui.c.Tr.DiffTitle
|
gui.Views.Main.Title = gui.c.Tr.DiffTitle
|
||||||
gui.Views.Main.Wrap = true
|
gui.Views.Main.Wrap = true
|
||||||
gui.Views.Main.FgColor = theme.GocuiDefaultTextColor
|
gui.Views.Main.FgColor = theme.GocuiDefaultTextColor
|
||||||
gui.Views.Main.IgnoreCarriageReturns = true
|
gui.Views.Main.IgnoreCarriageReturns = true
|
||||||
|
gui.Views.Main.CanScrollPastBottom = gui.c.UserConfig.Gui.ScrollPastBottom
|
||||||
|
|
||||||
gui.Views.Limit.Title = gui.c.Tr.NotEnoughSpace
|
gui.Views.Limit.Title = gui.c.Tr.NotEnoughSpace
|
||||||
gui.Views.Limit.Wrap = true
|
gui.Views.Limit.Wrap = true
|
||||||
|
@ -98,21 +98,15 @@ func (gui *Gui) getManager(view *gocui.View) *tasks.ViewBufferManager {
|
|||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
// Need to check if the content of the view is well past the origin.
|
// Need to check if the content of the view is well past the origin.
|
||||||
// It would be better to use .ViewLinesHeight here (given it considers
|
linesHeight := view.ViewLinesHeight()
|
||||||
// wrapping) but when this function is called they haven't been written to yet.
|
|
||||||
linesHeight := view.LinesHeight()
|
|
||||||
_, height := view.Size()
|
|
||||||
_, originY := view.Origin()
|
_, originY := view.Origin()
|
||||||
if linesHeight < originY {
|
if linesHeight < originY {
|
||||||
newOriginY := linesHeight - height
|
newOriginY := linesHeight
|
||||||
if newOriginY < 0 {
|
|
||||||
newOriginY = 0
|
|
||||||
}
|
|
||||||
err := view.SetOrigin(0, newOriginY)
|
err := view.SetOrigin(0, newOriginY)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view.FlushStaleCells()
|
view.FlushStaleCells()
|
||||||
|
@ -85,6 +85,8 @@ type IViewTrait interface {
|
|||||||
ViewPortYBounds() (int, int)
|
ViewPortYBounds() (int, int)
|
||||||
ScrollLeft()
|
ScrollLeft()
|
||||||
ScrollRight()
|
ScrollRight()
|
||||||
|
ScrollUp()
|
||||||
|
ScrollDown()
|
||||||
PageDelta() int
|
PageDelta() int
|
||||||
SelectedLineIdx() int
|
SelectedLineIdx() int
|
||||||
}
|
}
|
||||||
|
110
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
110
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
@ -743,6 +743,8 @@ func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showScrollbar, realScrollbarStart, realScrollbarEnd := calcRealScrollbarStartEnd(v)
|
||||||
for y := v.y0 + 1; y < v.y1 && y < g.maxY; y++ {
|
for y := v.y0 + 1; y < v.y1 && y < g.maxY; y++ {
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
continue
|
continue
|
||||||
@ -753,7 +755,9 @@ func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v.x1 > -1 && v.x1 < g.maxX {
|
if v.x1 > -1 && v.x1 < g.maxX {
|
||||||
if err := g.SetRune(v.x1, y, runeV, fgColor, bgColor); err != nil {
|
runeToPrint := calcScrollbarRune(showScrollbar, realScrollbarStart, realScrollbarEnd, v.y0+1, v.y1-1, y, runeV)
|
||||||
|
|
||||||
|
if err := g.SetRune(v.x1, y, runeToPrint, fgColor, bgColor); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -761,6 +765,44 @@ func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calcScrollbarRune(showScrollbar bool, scrollbarStart int, scrollbarEnd int, rangeStart int, rangeEnd int, position int, runeV rune) rune {
|
||||||
|
if !showScrollbar {
|
||||||
|
return runeV
|
||||||
|
} else if position == rangeStart {
|
||||||
|
return '▲'
|
||||||
|
} else if position == rangeEnd {
|
||||||
|
return '▼'
|
||||||
|
} else if position > scrollbarStart && position < scrollbarEnd {
|
||||||
|
return '█'
|
||||||
|
} else if position > rangeStart && position < rangeEnd {
|
||||||
|
// keeping this as a separate branch in case we later want to render something different here.
|
||||||
|
return runeV
|
||||||
|
} else {
|
||||||
|
return runeV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcRealScrollbarStartEnd(v *View) (bool, int, int) {
|
||||||
|
height := v.InnerHeight() + 1
|
||||||
|
fullHeight := v.ViewLinesHeight() - v.scrollMargin()
|
||||||
|
|
||||||
|
if v.CanScrollPastBottom {
|
||||||
|
fullHeight += height
|
||||||
|
}
|
||||||
|
|
||||||
|
if height < 2 || height >= fullHeight {
|
||||||
|
return false, 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
originY := v.OriginY()
|
||||||
|
scrollbarStart, scrollbarHeight := calcScrollbar(fullHeight, height, originY, height-1)
|
||||||
|
top := v.y0 + 1
|
||||||
|
realScrollbarStart := top + scrollbarStart
|
||||||
|
realScrollbarEnd := realScrollbarStart + scrollbarHeight
|
||||||
|
|
||||||
|
return true, realScrollbarStart, realScrollbarEnd
|
||||||
|
}
|
||||||
|
|
||||||
func cornerRune(index byte) rune {
|
func cornerRune(index byte) rune {
|
||||||
return []rune{' ', '│', '│', '│', '─', '┘', '┐', '┤', '─', '└', '┌', '├', '├', '┴', '┬', '┼'}[index]
|
return []rune{' ', '│', '│', '│', '─', '┘', '┐', '┤', '─', '└', '┌', '├', '├', '┴', '┬', '┼'}[index]
|
||||||
}
|
}
|
||||||
@ -1014,6 +1056,40 @@ func (g *Gui) draw(v *View) error {
|
|||||||
if !v.Visible || v.y1 < v.y0 {
|
if !v.Visible || v.y1 < v.y0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if g.Cursor {
|
||||||
|
if curview := g.currentView; curview != nil {
|
||||||
|
vMaxX, vMaxY := curview.Size()
|
||||||
|
if curview.cx < 0 {
|
||||||
|
curview.cx = 0
|
||||||
|
} else if curview.cx >= vMaxX {
|
||||||
|
curview.cx = vMaxX - 1
|
||||||
|
}
|
||||||
|
if curview.cy < 0 {
|
||||||
|
curview.cy = 0
|
||||||
|
} else if curview.cy >= vMaxY {
|
||||||
|
curview.cy = vMaxY - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
gMaxX, gMaxY := g.Size()
|
||||||
|
cx, cy := curview.x0+curview.cx+1, curview.y0+curview.cy+1
|
||||||
|
// This test probably doesn't need to be here.
|
||||||
|
// tcell is hiding cursor by setting coordinates outside of screen.
|
||||||
|
// Keeping it here for now, as I'm not 100% sure :)
|
||||||
|
if cx >= 0 && cx < gMaxX && cy >= 0 && cy < gMaxY {
|
||||||
|
Screen.ShowCursor(cx, cy)
|
||||||
|
} else {
|
||||||
|
Screen.HideCursor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Screen.HideCursor()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := v.draw(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if v.Frame {
|
if v.Frame {
|
||||||
var fgColor, bgColor, frameColor Attribute
|
var fgColor, bgColor, frameColor Attribute
|
||||||
if g.Highlight && v == g.currentView {
|
if g.Highlight && v == g.currentView {
|
||||||
@ -1057,38 +1133,6 @@ func (g *Gui) draw(v *View) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.Cursor {
|
|
||||||
if curview := g.currentView; curview != nil {
|
|
||||||
vMaxX, vMaxY := curview.Size()
|
|
||||||
if curview.cx < 0 {
|
|
||||||
curview.cx = 0
|
|
||||||
} else if curview.cx >= vMaxX {
|
|
||||||
curview.cx = vMaxX - 1
|
|
||||||
}
|
|
||||||
if curview.cy < 0 {
|
|
||||||
curview.cy = 0
|
|
||||||
} else if curview.cy >= vMaxY {
|
|
||||||
curview.cy = vMaxY - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
gMaxX, gMaxY := g.Size()
|
|
||||||
cx, cy := curview.x0+curview.cx+1, curview.y0+curview.cy+1
|
|
||||||
// This test probably doesn't need to be here.
|
|
||||||
// tcell is hiding cursor by setting coordinates outside of screen.
|
|
||||||
// Keeping it here for now, as I'm not 100% sure :)
|
|
||||||
if cx >= 0 && cx < gMaxX && cy >= 0 && cy < gMaxY {
|
|
||||||
Screen.ShowCursor(cx, cy)
|
|
||||||
} else {
|
|
||||||
Screen.HideCursor()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Screen.HideCursor()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := v.draw(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
vendor/github.com/jesseduffield/gocui/scrollbar.go
generated
vendored
Normal file
33
vendor/github.com/jesseduffield/gocui/scrollbar.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package gocui
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
// returns start and height of scrollbar
|
||||||
|
// `max` is the maximum possible value of `position`
|
||||||
|
func calcScrollbar(listSize int, pageSize int, position int, scrollAreaSize int) (int, int) {
|
||||||
|
height := calcScrollbarHeight(listSize, pageSize, scrollAreaSize)
|
||||||
|
// assume we can't scroll past the last item
|
||||||
|
maxPosition := listSize - pageSize
|
||||||
|
if maxPosition <= 0 {
|
||||||
|
return 0, height
|
||||||
|
}
|
||||||
|
if position == maxPosition {
|
||||||
|
return scrollAreaSize - height, height
|
||||||
|
}
|
||||||
|
// we only want to show the scrollbar at the top or bottom positions if we're at the end. Hence the .Ceil (for moving the scrollbar once we scroll down) and the -1 (for pretending there's a smaller range than we actually have, with the above condition ensuring we snap to the bottom once we're at the end of the list)
|
||||||
|
start := int(math.Ceil(((float64(position) / float64(maxPosition)) * float64(scrollAreaSize-height-1))))
|
||||||
|
return start, height
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcScrollbarHeight(listSize int, pageSize int, scrollAreaSize int) int {
|
||||||
|
if pageSize >= listSize {
|
||||||
|
return scrollAreaSize
|
||||||
|
}
|
||||||
|
height := int((float64(pageSize) / float64(listSize)) * float64(scrollAreaSize))
|
||||||
|
minHeight := 2
|
||||||
|
if height < minHeight {
|
||||||
|
return minHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
return height
|
||||||
|
}
|
69
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
69
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -158,6 +158,9 @@ type View struct {
|
|||||||
|
|
||||||
// something like '1 of 20' for a list view
|
// something like '1 of 20' for a list view
|
||||||
Footer string
|
Footer string
|
||||||
|
|
||||||
|
// if true, the user can scroll all the way past the last item until it appears at the top of the view
|
||||||
|
CanScrollPastBottom bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// call this in the event of a view resize, or if you want to render new content
|
// call this in the event of a view resize, or if you want to render new content
|
||||||
@ -1287,3 +1290,69 @@ func (v *View) OverwriteLines(y int, content string) {
|
|||||||
lines := strings.Replace(content, "\n", "\x1b[K\n", -1)
|
lines := strings.Replace(content, "\n", "\x1b[K\n", -1)
|
||||||
v.writeString(lines)
|
v.writeString(lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) ScrollUp(amount int) {
|
||||||
|
newOy := v.oy - amount
|
||||||
|
if newOy < 0 {
|
||||||
|
newOy = 0
|
||||||
|
}
|
||||||
|
v.oy = newOy
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensures we don't scroll past the end of the view's content
|
||||||
|
func (v *View) ScrollDown(amount int) {
|
||||||
|
adjustedAmount := v.adjustDownwardScrollAmount(amount)
|
||||||
|
if adjustedAmount > 0 {
|
||||||
|
v.oy += adjustedAmount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ScrollLeft(amount int) {
|
||||||
|
newOx := v.ox - amount
|
||||||
|
if newOx < 0 {
|
||||||
|
newOx = 0
|
||||||
|
}
|
||||||
|
v.ox = newOx
|
||||||
|
}
|
||||||
|
|
||||||
|
// not applying any limits to this
|
||||||
|
func (v *View) ScrollRight(amount int) {
|
||||||
|
v.ox += amount
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) adjustDownwardScrollAmount(scrollHeight int) int {
|
||||||
|
_, oy := v.Origin()
|
||||||
|
y := oy
|
||||||
|
if !v.CanScrollPastBottom {
|
||||||
|
_, sy := v.Size()
|
||||||
|
y += sy
|
||||||
|
}
|
||||||
|
scrollableLines := v.ViewLinesHeight() - y
|
||||||
|
if scrollableLines < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
margin := v.scrollMargin()
|
||||||
|
if scrollableLines-margin < scrollHeight {
|
||||||
|
scrollHeight = scrollableLines - margin
|
||||||
|
}
|
||||||
|
if oy+scrollHeight < 0 {
|
||||||
|
return 0
|
||||||
|
} else {
|
||||||
|
return scrollHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scrollMargin is about how many lines must still appear if you scroll
|
||||||
|
// all the way down. We'll subtract this from the total amount of scrollable lines
|
||||||
|
func (v *View) scrollMargin() int {
|
||||||
|
if v.CanScrollPastBottom {
|
||||||
|
// Setting to 2 because of the newline at the end of the file that we're likely showing.
|
||||||
|
// If we want to scroll past bottom outside the context of reading a file's contents,
|
||||||
|
// we should make this into a field on the view to be configured by the client.
|
||||||
|
// For now we're hardcoding it.
|
||||||
|
return 2
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -169,7 +169,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/index
|
||||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
|
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
|
||||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
|
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
|
||||||
# github.com/jesseduffield/gocui v0.3.1-0.20220415005542-2eb424ce3d0a
|
# github.com/jesseduffield/gocui v0.3.1-0.20220416053910-5b19e175bc67
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/jesseduffield/gocui
|
github.com/jesseduffield/gocui
|
||||||
# github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
# github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||||
|
Loading…
x
Reference in New Issue
Block a user