Compare commits
9 Commits
create-pul
...
focus-main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbd23107ef | ||
|
|
50426cda3a | ||
|
|
e031f437e9 | ||
|
|
9bd212aab1 | ||
|
|
9df81067e9 | ||
|
|
f31037864e | ||
|
|
03e060d82c | ||
|
|
f88b1942ae | ||
|
|
2e05ea57dc |
@@ -1,7 +1,6 @@
|
||||
package patch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
@@ -54,7 +53,7 @@ func (self *Patch) Lines() []*PatchLine {
|
||||
|
||||
// Returns the patch line index of the first line in the given hunk
|
||||
func (self *Patch) HunkStartIdx(hunkIndex int) int {
|
||||
hunkIndex = utils.Clamp(hunkIndex, 0, len(self.hunks)-1)
|
||||
hunkIndex = lo.Clamp(hunkIndex, 0, len(self.hunks)-1)
|
||||
|
||||
result := len(self.header)
|
||||
for i := 0; i < hunkIndex; i++ {
|
||||
@@ -65,7 +64,7 @@ func (self *Patch) HunkStartIdx(hunkIndex int) int {
|
||||
|
||||
// Returns the patch line index of the last line in the given hunk
|
||||
func (self *Patch) HunkEndIdx(hunkIndex int) int {
|
||||
hunkIndex = utils.Clamp(hunkIndex, 0, len(self.hunks)-1)
|
||||
hunkIndex = lo.Clamp(hunkIndex, 0, len(self.hunks)-1)
|
||||
|
||||
return self.HunkStartIdx(hunkIndex) + self.hunks[hunkIndex].lineCount() - 1
|
||||
}
|
||||
@@ -118,7 +117,7 @@ func (self *Patch) HunkContainingLine(idx int) int {
|
||||
|
||||
// Returns the patch line index of the next change (i.e. addition or deletion).
|
||||
func (self *Patch) GetNextChangeIdx(idx int) int {
|
||||
idx = utils.Clamp(idx, 0, self.LineCount()-1)
|
||||
idx = lo.Clamp(idx, 0, self.LineCount()-1)
|
||||
|
||||
lines := self.Lines()
|
||||
|
||||
|
||||
@@ -375,6 +375,7 @@ type KeybindingUniversalConfig struct {
|
||||
NextBlockAlt2 string `yaml:"nextBlock-alt2"`
|
||||
PrevBlockAlt2 string `yaml:"prevBlock-alt2"`
|
||||
JumpToBlock []string `yaml:"jumpToBlock"`
|
||||
FocusMainView string `yaml:"focusMainView"`
|
||||
NextMatch string `yaml:"nextMatch"`
|
||||
PrevMatch string `yaml:"prevMatch"`
|
||||
StartSearch string `yaml:"startSearch"`
|
||||
@@ -816,6 +817,7 @@ func GetDefaultConfig() *UserConfig {
|
||||
PrevBlockAlt2: "<backtab>",
|
||||
NextBlockAlt2: "<tab>",
|
||||
JumpToBlock: []string{"1", "2", "3", "4", "5"},
|
||||
FocusMainView: "0",
|
||||
NextMatch: "n",
|
||||
PrevMatch: "N",
|
||||
StartSearch: "/",
|
||||
|
||||
@@ -24,6 +24,8 @@ const (
|
||||
STASH_CONTEXT_KEY types.ContextKey = "stash"
|
||||
NORMAL_MAIN_CONTEXT_KEY types.ContextKey = "normal"
|
||||
NORMAL_SECONDARY_CONTEXT_KEY types.ContextKey = "normalSecondary"
|
||||
DIFF_MAIN_CONTEXT_KEY types.ContextKey = "diff"
|
||||
DIFF_SECONDARY_CONTEXT_KEY types.ContextKey = "diffSecondary"
|
||||
STAGING_MAIN_CONTEXT_KEY types.ContextKey = "staging"
|
||||
STAGING_SECONDARY_CONTEXT_KEY types.ContextKey = "stagingSecondary"
|
||||
PATCH_BUILDING_MAIN_CONTEXT_KEY types.ContextKey = "patchBuilding"
|
||||
@@ -100,6 +102,8 @@ type ContextTree struct {
|
||||
Suggestions *SuggestionsContext
|
||||
Normal types.Context
|
||||
NormalSecondary types.Context
|
||||
Diff types.Context
|
||||
DiffSecondary types.Context
|
||||
Staging *PatchExplorerContext
|
||||
StagingSecondary *PatchExplorerContext
|
||||
CustomPatchBuilder *PatchExplorerContext
|
||||
@@ -149,6 +153,8 @@ func (self *ContextTree) Flatten() []types.Context {
|
||||
self.Staging,
|
||||
self.CustomPatchBuilderSecondary,
|
||||
self.CustomPatchBuilder,
|
||||
self.Diff,
|
||||
self.DiffSecondary,
|
||||
self.NormalSecondary,
|
||||
self.Normal,
|
||||
|
||||
|
||||
53
pkg/gui/context/diff_context.go
Normal file
53
pkg/gui/context/diff_context.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
type DiffContext struct {
|
||||
*SimpleContext
|
||||
*SearchTrait
|
||||
|
||||
c *ContextCommon
|
||||
}
|
||||
|
||||
var _ types.ISearchableContext = (*DiffContext)(nil)
|
||||
|
||||
func NewDiffContext(
|
||||
view *gocui.View,
|
||||
windowName string,
|
||||
key types.ContextKey,
|
||||
|
||||
c *ContextCommon,
|
||||
) *DiffContext {
|
||||
ctx := &DiffContext{
|
||||
SimpleContext: NewSimpleContext(
|
||||
NewBaseContext(NewBaseContextOpts{
|
||||
Kind: types.MAIN_CONTEXT,
|
||||
View: view,
|
||||
WindowName: windowName,
|
||||
Key: key,
|
||||
Focusable: true,
|
||||
HighlightOnFocus: true,
|
||||
})),
|
||||
SearchTrait: NewSearchTrait(c),
|
||||
c: c,
|
||||
}
|
||||
|
||||
// TODO: copied from PatchExplorerContext. Do we need something like this?
|
||||
// ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(
|
||||
// func(selectedLineIdx int) error {
|
||||
// ctx.GetMutex().Lock()
|
||||
// defer ctx.GetMutex().Unlock()
|
||||
// ctx.NavigateTo(ctx.c.Context().IsCurrent(ctx), selectedLineIdx)
|
||||
// return nil
|
||||
// }),
|
||||
// )
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (self *DiffContext) ModelSearchResults(searchStr string, caseSensitive bool) []gocui.SearchPosition {
|
||||
return nil
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func (self *ListRenderer) ModelIndexToViewIndex(modelIndex int) int {
|
||||
}
|
||||
|
||||
func (self *ListRenderer) ViewIndexToModelIndex(viewIndex int) int {
|
||||
viewIndex = utils.Clamp(viewIndex, 0, self.list.Len()+self.numNonModelItems)
|
||||
viewIndex = lo.Clamp(viewIndex, 0, self.list.Len()+self.numNonModelItems)
|
||||
if self.modelIndicesByViewIndex != nil {
|
||||
return self.modelIndicesByViewIndex[viewIndex]
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ func NewContextTree(c *ContextCommon) *ContextTree {
|
||||
Focusable: false,
|
||||
}),
|
||||
),
|
||||
Diff: NewDiffContext(c.Views().Diff, "main", DIFF_MAIN_CONTEXT_KEY, c),
|
||||
DiffSecondary: NewDiffContext(c.Views().DiffSecondary, "secondary", DIFF_SECONDARY_CONTEXT_KEY, c),
|
||||
Staging: NewPatchExplorerContext(
|
||||
c.Views().Staging,
|
||||
"main",
|
||||
|
||||
@@ -3,6 +3,7 @@ package traits
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type RangeSelectMode int
|
||||
@@ -85,7 +86,7 @@ func (self *ListCursor) clampValue(value int) int {
|
||||
clampedValue := -1
|
||||
length := self.getLength()
|
||||
if length > 0 {
|
||||
clampedValue = utils.Clamp(value, 0, length-1)
|
||||
clampedValue = lo.Clamp(value, 0, length-1)
|
||||
}
|
||||
|
||||
return clampedValue
|
||||
|
||||
@@ -181,6 +181,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
||||
contextLinesController := controllers.NewContextLinesController(common)
|
||||
renameSimilarityThresholdController := controllers.NewRenameSimilarityThresholdController(common)
|
||||
verticalScrollControllerFactory := controllers.NewVerticalScrollControllerFactory(common, &gui.viewBufferManagerMap)
|
||||
viewSelectionControllerFactory := controllers.NewViewSelectionControllerFactory(common, &gui.viewBufferManagerMap)
|
||||
|
||||
branchesController := controllers.NewBranchesController(common)
|
||||
gitFlowController := controllers.NewGitFlowController(common)
|
||||
@@ -189,6 +190,8 @@ func (gui *Gui) resetHelpersAndControllers() {
|
||||
patchExplorerControllerFactory := controllers.NewPatchExplorerControllerFactory(common)
|
||||
stagingController := controllers.NewStagingController(common, gui.State.Contexts.Staging, gui.State.Contexts.StagingSecondary, false)
|
||||
stagingSecondaryController := controllers.NewStagingController(common, gui.State.Contexts.StagingSecondary, gui.State.Contexts.Staging, true)
|
||||
diffController := controllers.NewDiffController(common, gui.State.Contexts.Diff, gui.State.Contexts.DiffSecondary, &gui.viewBufferManagerMap)
|
||||
diffSecondaryController := controllers.NewDiffController(common, gui.State.Contexts.DiffSecondary, gui.State.Contexts.Diff, &gui.viewBufferManagerMap)
|
||||
patchBuildingController := controllers.NewPatchBuildingController(common)
|
||||
snakeController := controllers.NewSnakeController(common)
|
||||
reflogCommitsController := controllers.NewReflogCommitsController(common)
|
||||
@@ -306,6 +309,18 @@ func (gui *Gui) resetHelpersAndControllers() {
|
||||
mergeConflictsController,
|
||||
)
|
||||
|
||||
controllers.AttachControllers(gui.State.Contexts.Diff,
|
||||
diffController,
|
||||
verticalScrollControllerFactory.Create(gui.State.Contexts.Diff),
|
||||
viewSelectionControllerFactory.Create(gui.State.Contexts.Diff),
|
||||
)
|
||||
|
||||
controllers.AttachControllers(gui.State.Contexts.DiffSecondary,
|
||||
diffSecondaryController,
|
||||
verticalScrollControllerFactory.Create(gui.State.Contexts.DiffSecondary),
|
||||
viewSelectionControllerFactory.Create(gui.State.Contexts.DiffSecondary),
|
||||
)
|
||||
|
||||
controllers.AttachControllers(gui.State.Contexts.Files,
|
||||
filesController,
|
||||
)
|
||||
|
||||
92
pkg/gui/controllers/diff_controller.go
Normal file
92
pkg/gui/controllers/diff_controller.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/tasks"
|
||||
)
|
||||
|
||||
type DiffController struct {
|
||||
baseController
|
||||
c *ControllerCommon
|
||||
|
||||
context types.Context
|
||||
otherContext types.Context
|
||||
|
||||
viewBufferManagerMap *map[string]*tasks.ViewBufferManager
|
||||
}
|
||||
|
||||
var _ types.IController = &DiffController{}
|
||||
|
||||
func NewDiffController(
|
||||
c *ControllerCommon,
|
||||
context types.Context,
|
||||
otherContext types.Context,
|
||||
viewBufferManagerMap *map[string]*tasks.ViewBufferManager,
|
||||
) *DiffController {
|
||||
return &DiffController{
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
context: context,
|
||||
otherContext: otherContext,
|
||||
viewBufferManagerMap: viewBufferManagerMap,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *DiffController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
return []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
|
||||
Handler: self.TogglePanel,
|
||||
Description: self.c.Tr.ToggleStagingView,
|
||||
Tooltip: self.c.Tr.ToggleStagingViewTooltip,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Handler: self.Escape,
|
||||
Description: self.c.Tr.ExitCustomPatchBuilder,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (self *DiffController) Context() types.Context {
|
||||
return self.context
|
||||
}
|
||||
|
||||
func (self *DiffController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
|
||||
return []*gocui.ViewMouseBinding{}
|
||||
}
|
||||
|
||||
func (self *DiffController) GetOnFocus() func(types.OnFocusOpts) {
|
||||
return func(opts types.OnFocusOpts) {
|
||||
self.c.Helpers().Diff.RenderFilesViewDiff(self.c.MainViewPairs().Diff)
|
||||
if opts.ClickedWindowName == "main" {
|
||||
if manager, ok := (*self.viewBufferManagerMap)[self.context.GetViewName()]; ok {
|
||||
// TODO: doesn't work the first time after launching. Need to
|
||||
// find a way to construct the ViewBufferManager for this view
|
||||
// earlier.
|
||||
manager.ReadLines(opts.ClickedViewLineIdx - self.context.GetView().LinesHeight() + 1)
|
||||
}
|
||||
self.context.GetView().FocusPoint(0, opts.ClickedViewLineIdx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *DiffController) GetOnFocusLost() func(types.OnFocusLostOpts) {
|
||||
return func(opts types.OnFocusLostOpts) {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *DiffController) TogglePanel() error {
|
||||
if self.otherContext.GetView().Visible {
|
||||
self.c.Context().Push(self.otherContext)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *DiffController) Escape() error {
|
||||
self.c.Context().Pop()
|
||||
return nil
|
||||
}
|
||||
@@ -112,6 +112,11 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
Handler: self.refresh,
|
||||
Description: self.c.Tr.RefreshFiles,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.FocusMainView),
|
||||
Handler: self.focusMainView,
|
||||
Description: self.c.Tr.FocusMainView,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Files.StashAllChanges),
|
||||
Handler: self.stash,
|
||||
@@ -229,19 +234,7 @@ func (self *FilesController) GetOnRenderToMain() func() {
|
||||
self.c.Helpers().Diff.WithDiffModeCheck(func() {
|
||||
node := self.context().GetSelected()
|
||||
|
||||
if node == nil {
|
||||
self.c.RenderToMainViews(types.RefreshMainOpts{
|
||||
Pair: self.c.MainViewPairs().Normal,
|
||||
Main: &types.ViewUpdateOpts{
|
||||
Title: self.c.Tr.DiffTitle,
|
||||
SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(),
|
||||
Task: types.NewRenderStringTask(self.c.Tr.NoChangedFiles),
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if node.File != nil && node.File.HasInlineMergeConflicts {
|
||||
if node != nil && node.File != nil && node.File.HasInlineMergeConflicts {
|
||||
hasConflicts, err := self.c.Helpers().MergeConflicts.SetMergeState(node.GetPath())
|
||||
if err != nil {
|
||||
return
|
||||
@@ -256,43 +249,11 @@ func (self *FilesController) GetOnRenderToMain() func() {
|
||||
self.c.Helpers().MergeConflicts.ResetMergeState()
|
||||
|
||||
pair := self.c.MainViewPairs().Normal
|
||||
if node.File != nil {
|
||||
if node != nil && node.File != nil {
|
||||
pair = self.c.MainViewPairs().Staging
|
||||
}
|
||||
|
||||
split := self.c.UserConfig().Gui.SplitDiff == "always" || (node.GetHasUnstagedChanges() && node.GetHasStagedChanges())
|
||||
mainShowsStaged := !split && node.GetHasStagedChanges()
|
||||
|
||||
cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(node, false, mainShowsStaged)
|
||||
title := self.c.Tr.UnstagedChanges
|
||||
if mainShowsStaged {
|
||||
title = self.c.Tr.StagedChanges
|
||||
}
|
||||
refreshOpts := types.RefreshMainOpts{
|
||||
Pair: pair,
|
||||
Main: &types.ViewUpdateOpts{
|
||||
Task: types.NewRunPtyTask(cmdObj.GetCmd()),
|
||||
SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(),
|
||||
Title: title,
|
||||
},
|
||||
}
|
||||
|
||||
if split {
|
||||
cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(node, false, true)
|
||||
|
||||
title := self.c.Tr.StagedChanges
|
||||
if mainShowsStaged {
|
||||
title = self.c.Tr.UnstagedChanges
|
||||
}
|
||||
|
||||
refreshOpts.Secondary = &types.ViewUpdateOpts{
|
||||
Title: title,
|
||||
SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(),
|
||||
Task: types.NewRunPtyTask(cmdObj.GetCmd()),
|
||||
}
|
||||
}
|
||||
|
||||
self.c.RenderToMainViews(refreshOpts)
|
||||
self.c.Helpers().Diff.RenderFilesViewDiff(pair)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -659,6 +620,16 @@ func (self *FilesController) refresh() error {
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
}
|
||||
|
||||
func (self *FilesController) focusMainView() error {
|
||||
mainView := self.c.Helpers().Window.TopViewInWindow("main", false)
|
||||
lineIdx := mainView.OriginY() + mainView.Height()/2
|
||||
lineIdx = lo.Clamp(lineIdx, 0, mainView.LinesHeight()-1)
|
||||
self.c.Context().Push(self.c.Contexts().Diff,
|
||||
types.OnFocusOpts{ClickedWindowName: "main", ClickedViewLineIdx: lineIdx})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) handleAmendCommitPress() error {
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.AmendLastCommitTitle,
|
||||
|
||||
@@ -171,3 +171,68 @@ func (self *DiffHelper) OpenDiffToolForRef(selectedRef types.Ref) error {
|
||||
}))
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *DiffHelper) RenderFilesViewDiff(pair types.MainContextPair) {
|
||||
self.WithDiffModeCheck(func() {
|
||||
node := self.c.Contexts().Files.GetSelected()
|
||||
|
||||
if node == nil {
|
||||
self.c.RenderToMainViews(types.RefreshMainOpts{
|
||||
Pair: self.c.MainViewPairs().Normal,
|
||||
Main: &types.ViewUpdateOpts{
|
||||
Title: self.c.Tr.DiffTitle,
|
||||
SubTitle: self.IgnoringWhitespaceSubTitle(),
|
||||
Task: types.NewRenderStringTask(self.c.Tr.NoChangedFiles),
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
split := self.c.UserConfig().Gui.SplitDiff == "always" || (node.GetHasUnstagedChanges() && node.GetHasStagedChanges())
|
||||
mainShowsStaged := !split && node.GetHasStagedChanges()
|
||||
|
||||
cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(node, false, mainShowsStaged)
|
||||
title := self.c.Tr.UnstagedChanges
|
||||
if mainShowsStaged {
|
||||
title = self.c.Tr.StagedChanges
|
||||
}
|
||||
|
||||
// >>>>> HACK
|
||||
if pair == self.c.MainViewPairs().Diff {
|
||||
title += " (focused)"
|
||||
}
|
||||
// <<<<< HACK
|
||||
|
||||
refreshOpts := types.RefreshMainOpts{
|
||||
Pair: pair,
|
||||
Main: &types.ViewUpdateOpts{
|
||||
Task: types.NewRunPtyTask(cmdObj.GetCmd()),
|
||||
SubTitle: self.IgnoringWhitespaceSubTitle(),
|
||||
Title: title,
|
||||
},
|
||||
}
|
||||
|
||||
if split {
|
||||
cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(node, false, true)
|
||||
|
||||
title := self.c.Tr.StagedChanges
|
||||
if mainShowsStaged {
|
||||
title = self.c.Tr.UnstagedChanges
|
||||
}
|
||||
|
||||
// >>>>> HACK
|
||||
if pair == self.c.MainViewPairs().Diff {
|
||||
title += " (focused)"
|
||||
}
|
||||
// <<<<< HACK
|
||||
|
||||
refreshOpts.Secondary = &types.ViewUpdateOpts{
|
||||
Title: title,
|
||||
SubTitle: self.IgnoringWhitespaceSubTitle(),
|
||||
Task: types.NewRunPtyTask(cmdObj.GetCmd()),
|
||||
}
|
||||
}
|
||||
|
||||
self.c.RenderToMainViews(refreshOpts)
|
||||
})
|
||||
}
|
||||
|
||||
108
pkg/gui/controllers/view_selection_controller.go
Normal file
108
pkg/gui/controllers/view_selection_controller.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/tasks"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type ViewSelectionControllerFactory struct {
|
||||
c *ControllerCommon
|
||||
viewBufferManagerMap *map[string]*tasks.ViewBufferManager
|
||||
}
|
||||
|
||||
func NewViewSelectionControllerFactory(c *ControllerCommon, viewBufferManagerMap *map[string]*tasks.ViewBufferManager) *ViewSelectionControllerFactory {
|
||||
return &ViewSelectionControllerFactory{
|
||||
c: c,
|
||||
viewBufferManagerMap: viewBufferManagerMap,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ViewSelectionControllerFactory) Create(context types.Context) types.IController {
|
||||
return &ViewSelectionController{
|
||||
baseController: baseController{},
|
||||
c: self.c,
|
||||
context: context,
|
||||
viewBufferManagerMap: self.viewBufferManagerMap,
|
||||
}
|
||||
}
|
||||
|
||||
type ViewSelectionController struct {
|
||||
baseController
|
||||
c *ControllerCommon
|
||||
|
||||
context types.Context
|
||||
viewBufferManagerMap *map[string]*tasks.ViewBufferManager
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) Context() types.Context {
|
||||
return self.context
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
return []*types.Binding{
|
||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Handler: self.handlePrevLine},
|
||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Handler: self.handlePrevLine},
|
||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Handler: self.handleNextLine},
|
||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Handler: self.handleNextLine},
|
||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Handler: self.handlePrevPage, Description: self.c.Tr.PrevPage},
|
||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Handler: self.handleNextPage, Description: self.c.Tr.NextPage},
|
||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Handler: self.handleGotoTop, Description: self.c.Tr.GotoTop},
|
||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Description: self.c.Tr.GotoBottom, Handler: self.handleGotoBottom},
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
|
||||
return []*gocui.ViewMouseBinding{}
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) handleLineChange(delta int) {
|
||||
if delta > 0 {
|
||||
if manager, ok := (*self.viewBufferManagerMap)[self.context.GetViewName()]; ok {
|
||||
manager.ReadLines(delta)
|
||||
}
|
||||
}
|
||||
|
||||
v := self.Context().GetView()
|
||||
lineIdxBefore := v.CursorY() + v.OriginY()
|
||||
lineIdxAfter := lo.Clamp(lineIdxBefore+delta, 0, v.LinesHeight()-1)
|
||||
if delta == -1 {
|
||||
checkScrollUp(self.Context().GetViewTrait(), self.c.UserConfig(), lineIdxBefore, lineIdxAfter)
|
||||
} else if delta == 1 {
|
||||
checkScrollDown(self.Context().GetViewTrait(), self.c.UserConfig(), lineIdxBefore, lineIdxAfter)
|
||||
}
|
||||
v.FocusPoint(0, lineIdxAfter)
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) handlePrevLine() error {
|
||||
self.handleLineChange(-1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) handleNextLine() error {
|
||||
self.handleLineChange(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) handlePrevPage() error {
|
||||
self.handleLineChange(-self.context.GetViewTrait().PageDelta())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) handleNextPage() error {
|
||||
self.handleLineChange(self.context.GetViewTrait().PageDelta())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) handleGotoTop() error {
|
||||
v := self.Context().GetView()
|
||||
v.FocusPoint(0, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ViewSelectionController) handleGotoBottom() error {
|
||||
v := self.Context().GetView()
|
||||
v.FocusPoint(0, v.LinesHeight()-1)
|
||||
return nil
|
||||
}
|
||||
@@ -122,6 +122,7 @@ func (self *guiCommon) RenderToMainViews(opts types.RefreshMainOpts) {
|
||||
func (self *guiCommon) MainViewPairs() types.MainViewPairs {
|
||||
return types.MainViewPairs{
|
||||
Normal: self.gui.normalMainContextPair(),
|
||||
Diff: self.gui.diffMainContextPair(),
|
||||
Staging: self.gui.stagingMainContextPair(),
|
||||
PatchBuilding: self.gui.patchBuildingMainContextPair(),
|
||||
MergeConflicts: self.gui.mergingMainContextPair(),
|
||||
|
||||
@@ -79,6 +79,13 @@ func (gui *Gui) normalMainContextPair() types.MainContextPair {
|
||||
)
|
||||
}
|
||||
|
||||
func (gui *Gui) diffMainContextPair() types.MainContextPair {
|
||||
return types.NewMainContextPair(
|
||||
gui.State.Contexts.Diff,
|
||||
gui.State.Contexts.DiffSecondary,
|
||||
)
|
||||
}
|
||||
|
||||
func (gui *Gui) stagingMainContextPair() types.MainContextPair {
|
||||
return types.NewMainContextPair(
|
||||
gui.State.Contexts.Staging,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// State represents the selection state of the merge conflict context.
|
||||
@@ -37,14 +38,14 @@ func (s *State) setConflictIndex(index int) {
|
||||
if len(s.conflicts) == 0 {
|
||||
s.conflictIndex = 0
|
||||
} else {
|
||||
s.conflictIndex = utils.Clamp(index, 0, len(s.conflicts)-1)
|
||||
s.conflictIndex = lo.Clamp(index, 0, len(s.conflicts)-1)
|
||||
}
|
||||
s.setSelectionIndex(s.selectionIndex)
|
||||
}
|
||||
|
||||
func (s *State) setSelectionIndex(index int) {
|
||||
if selections := s.availableSelections(); len(selections) != 0 {
|
||||
s.selectionIndex = utils.Clamp(index, 0, len(selections)-1)
|
||||
s.selectionIndex = lo.Clamp(index, 0, len(selections)-1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ func NewMainContextPair(main Context, secondary Context) MainContextPair {
|
||||
|
||||
type MainViewPairs struct {
|
||||
Normal MainContextPair
|
||||
Diff MainContextPair
|
||||
MergeConflicts MainContextPair
|
||||
Staging MainContextPair
|
||||
PatchBuilding MainContextPair
|
||||
|
||||
@@ -17,6 +17,8 @@ type Views struct {
|
||||
|
||||
Main *gocui.View
|
||||
Secondary *gocui.View
|
||||
Diff *gocui.View
|
||||
DiffSecondary *gocui.View
|
||||
Staging *gocui.View
|
||||
StagingSecondary *gocui.View
|
||||
PatchBuilding *gocui.View
|
||||
|
||||
@@ -43,6 +43,8 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping {
|
||||
{viewPtr: &gui.Views.PatchBuilding, name: "patchBuilding"},
|
||||
{viewPtr: &gui.Views.PatchBuildingSecondary, name: "patchBuildingSecondary"},
|
||||
{viewPtr: &gui.Views.MergeConflicts, name: "mergeConflicts"},
|
||||
{viewPtr: &gui.Views.Diff, name: "diff"},
|
||||
{viewPtr: &gui.Views.DiffSecondary, name: "diffSecondary"},
|
||||
{viewPtr: &gui.Views.Secondary, name: "secondary"},
|
||||
{viewPtr: &gui.Views.Main, name: "main"},
|
||||
|
||||
@@ -72,6 +74,20 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping {
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) mainViews() []*gocui.View {
|
||||
return []*gocui.View{
|
||||
gui.Views.Main,
|
||||
gui.Views.Secondary,
|
||||
gui.Views.Diff,
|
||||
gui.Views.DiffSecondary,
|
||||
gui.Views.Staging,
|
||||
gui.Views.StagingSecondary,
|
||||
gui.Views.PatchBuilding,
|
||||
gui.Views.PatchBuildingSecondary,
|
||||
gui.Views.MergeConflicts,
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) createAllViews() error {
|
||||
var err error
|
||||
for _, mapping := range gui.orderedViewNameMappings() {
|
||||
@@ -113,7 +129,7 @@ func (gui *Gui) createAllViews() error {
|
||||
|
||||
gui.Views.Files.Title = gui.c.Tr.FilesTitle
|
||||
|
||||
for _, view := range []*gocui.View{gui.Views.Main, gui.Views.Secondary, gui.Views.Staging, gui.Views.StagingSecondary, gui.Views.PatchBuilding, gui.Views.PatchBuildingSecondary, gui.Views.MergeConflicts} {
|
||||
for _, view := range gui.mainViews() {
|
||||
view.Title = gui.c.Tr.DiffTitle
|
||||
view.Wrap = true
|
||||
view.IgnoreCarriageReturns = true
|
||||
@@ -201,7 +217,7 @@ func (gui *Gui) configureViewProperties() {
|
||||
(*mapping.viewPtr).InactiveViewSelBgColor = theme.GocuiInactiveViewSelectedLineBgColor
|
||||
}
|
||||
|
||||
for _, view := range []*gocui.View{gui.Views.Main, gui.Views.Secondary, gui.Views.Staging, gui.Views.StagingSecondary, gui.Views.PatchBuilding, gui.Views.PatchBuildingSecondary, gui.Views.MergeConflicts} {
|
||||
for _, view := range gui.mainViews() {
|
||||
view.CanScrollPastBottom = gui.c.UserConfig().Gui.ScrollPastBottom
|
||||
}
|
||||
|
||||
|
||||
@@ -237,6 +237,7 @@ type TranslationSet struct {
|
||||
IgnoreFile string
|
||||
ExcludeFile string
|
||||
RefreshFiles string
|
||||
FocusMainView string
|
||||
Merge string
|
||||
RegularMerge string
|
||||
MergeBranchTooltip string
|
||||
@@ -1219,6 +1220,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
IgnoreFile: `Add to .gitignore`,
|
||||
ExcludeFile: `Add to .git/info/exclude`,
|
||||
RefreshFiles: `Refresh files`,
|
||||
FocusMainView: "Focus main view",
|
||||
Merge: `Merge`,
|
||||
RegularMerge: "Regular merge",
|
||||
MergeBranchTooltip: "View options for merging the selected item into the current branch (regular merge, squash merge)",
|
||||
|
||||
@@ -39,15 +39,6 @@ func SortRange(x int, y int) (int, int) {
|
||||
return y, x
|
||||
}
|
||||
|
||||
func Clamp(x int, min int, max int) int {
|
||||
if x < min {
|
||||
return min
|
||||
} else if x > max {
|
||||
return max
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func AsJson(i interface{}) string {
|
||||
bytes, _ := json.MarshalIndent(i, "", " ")
|
||||
return string(bytes)
|
||||
|
||||
4
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
4
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@@ -529,9 +529,9 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) {
|
||||
}
|
||||
fgColor = fgColor | AttrBold
|
||||
if v.HighlightInactive {
|
||||
bgColor = bgColor | v.InactiveViewSelBgColor
|
||||
bgColor = (bgColor & AttrStyleBits) | v.InactiveViewSelBgColor
|
||||
} else {
|
||||
bgColor = bgColor | v.SelBgColor
|
||||
bgColor = (bgColor & AttrStyleBits) | v.SelBgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user