1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-19 21:28:28 +02:00
type safe view access
This commit is contained in:
Jesse Duffield 2021-04-04 23:51:59 +10:00
parent 5b0958a2fd
commit eaa2d792e1
36 changed files with 531 additions and 555 deletions

View File

@ -30,13 +30,13 @@ func (gui *Gui) handleBranchSelect() error {
var task updateTask
branch := gui.getSelectedBranch()
if branch == nil {
task = gui.createRenderStringTask(gui.Tr.NoBranchesThisRepo)
task = NewRenderStringTask(gui.Tr.NoBranchesThisRepo)
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(branch.Name),
)
task = gui.createRunPtyTask(cmd)
task = NewRunPtyTask(cmd)
}
return gui.refreshMainViews(refreshMainOpts{
@ -473,7 +473,7 @@ func (gui *Gui) currentBranch() *models.Branch {
}
func (gui *Gui) handleNewBranchOffCurrentItem() error {
context := gui.currentSideContext()
context := gui.currentSideListContext()
item, ok := context.GetSelectedItem()
if !ok {

View File

@ -24,7 +24,7 @@ func (gui *Gui) handleCopyCommit() error {
}
// get currently selected commit, add the sha to state.
context := gui.currentSideContext()
context := gui.currentSideListContext()
if context == nil {
return nil
}
@ -63,7 +63,7 @@ func (gui *Gui) cherryPickedCommitShaMap() map[string]bool {
}
func (gui *Gui) commitsListForContext() []*models.Commit {
context := gui.currentSideContext()
context := gui.currentSideListContext()
if context == nil {
return nil
}
@ -104,7 +104,7 @@ func (gui *Gui) handleCopyCommitRange() error {
}
// get currently selected commit, add the sha to state.
context := gui.currentSideContext()
context := gui.currentSideListContext()
if context == nil {
return nil
}
@ -169,7 +169,7 @@ func (gui *Gui) exitCherryPickingMode() error {
return gui.rerenderContextViewIfPresent(contextKey)
}
func (gui *Gui) rerenderContextViewIfPresent(contextKey string) error {
func (gui *Gui) rerenderContextViewIfPresent(contextKey ContextKey) error {
if contextKey == "" {
return nil
}
@ -184,7 +184,7 @@ func (gui *Gui) rerenderContextViewIfPresent(contextKey string) error {
return nil
}
if view.Context == contextKey {
if ContextKey(view.Context) == contextKey {
if err := context.HandleRender(); err != nil {
return err
}

View File

@ -45,7 +45,7 @@ func (gui *Gui) handleCommitFileSelect() error {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowFileDiffCmdStr(from, to, reverse, node.GetPath(), false),
)
task := gui.createRunPtyTask(cmd)
task := NewRunPtyTask(cmd)
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{
@ -287,7 +287,8 @@ func (gui *Gui) handleToggleCommitFileTreeView() error {
}
}
if gui.getCommitFilesView().Context == COMMIT_FILES_CONTEXT_KEY {
// TODO: pretty sure this view only ever has this context. Is this if condition necessary?
if gui.Views.CommitFiles.Context == COMMIT_FILES_CONTEXT_KEY {
if err := gui.State.Contexts.CommitFiles.HandleRender(); err != nil {
return err
}

View File

@ -23,8 +23,7 @@ func (gui *Gui) runSyncOrAsyncCommand(sub *exec.Cmd, err error) (bool, error) {
}
func (gui *Gui) handleCommitConfirm() error {
commitMessageView := gui.getCommitMessageView()
message := gui.trimmedContent(commitMessageView)
message := gui.trimmedContent(gui.Views.CommitMessage)
if message == "" {
return gui.createErrorPanel(gui.Tr.CommitWithoutMessageErr)
}
@ -41,7 +40,7 @@ func (gui *Gui) handleCommitConfirm() error {
return nil
}
gui.clearEditorView(commitMessageView)
gui.clearEditorView(gui.Views.CommitMessage)
_ = gui.returnFromContext()
return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
}
@ -73,6 +72,6 @@ func (gui *Gui) RenderCommitLength() {
if !gui.Config.GetUserConfig().Gui.CommitLength.Show {
return
}
v := gui.getCommitMessageView()
v.Subtitle = gui.getBufferLength(v)
gui.Views.CommitMessage.Subtitle = gui.getBufferLength(gui.Views.CommitMessage)
}

View File

@ -35,12 +35,12 @@ func (gui *Gui) handleCommitSelect() error {
var task updateTask
commit := gui.getSelectedLocalCommit()
if commit == nil {
task = gui.createRenderStringTask(gui.Tr.NoCommitsThisBranch)
task = NewRenderStringTask(gui.Tr.NoCommitsThisBranch)
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCmdStr(commit.Sha, gui.State.Modes.Filtering.GetPath()),
)
task = gui.createRunPtyTask(cmd)
task = NewRunPtyTask(cmd)
}
return gui.refreshMainViews(refreshMainOpts{

View File

@ -108,19 +108,17 @@ func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, func
}
}
func (gui *Gui) deleteConfirmationView() {
func (gui *Gui) clearConfirmationViewKeyBindings() {
keybindingConfig := gui.Config.GetUserConfig().Keybinding
_ = gui.g.DeleteKeybinding("confirmation", gui.getKey(keybindingConfig.Universal.Confirm), gocui.ModNone)
_ = gui.g.DeleteKeybinding("confirmation", gui.getKey(keybindingConfig.Universal.ConfirmAlt1), gocui.ModNone)
_ = gui.g.DeleteKeybinding("confirmation", gui.getKey(keybindingConfig.Universal.Return), gocui.ModNone)
_ = gui.g.DeleteView("confirmation")
}
func (gui *Gui) closeConfirmationPrompt(handlersManageFocus bool) error {
view := gui.getConfirmationView()
if view == nil {
return nil // if it's already been closed we can just return
// we've already closed it so we can just return
if !gui.Views.Confirmation.Visible {
return nil
}
if !handlersManageFocus {
@ -129,9 +127,9 @@ func (gui *Gui) closeConfirmationPrompt(handlersManageFocus bool) error {
}
}
gui.deleteConfirmationView()
_, _ = gui.g.SetViewOnBottom("suggestions")
gui.clearConfirmationViewKeyBindings()
gui.Views.Confirmation.Visible = false
gui.Views.Suggestions.Visible = false
return nil
}
@ -200,7 +198,7 @@ func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool, f
suggestionsView.FgColor = theme.GocuiDefaultTextColor
}
gui.setSuggestions([]*types.Suggestion{})
_, _ = gui.g.SetViewOnTop("suggestions")
suggestionsView.Visible = true
}
gui.g.Update(func(g *gocui.Gui) error {
@ -211,10 +209,9 @@ func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool, f
func (gui *Gui) createPopupPanel(opts createPopupPanelOpts) error {
gui.g.Update(func(g *gocui.Gui) error {
// delete the existing confirmation panel if it exists
if view, _ := g.View("confirmation"); view != nil {
gui.deleteConfirmationView()
}
// remove any previous keybindings
gui.clearConfirmationViewKeyBindings()
confirmationView, err := gui.prepareConfirmationPanel(opts.title, opts.prompt, opts.hasLoader, opts.findSuggestionsFunc)
if err != nil {
return err
@ -251,7 +248,7 @@ func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error {
gui.renderString("options", actions)
var onConfirm func() error
if opts.handleConfirmPrompt != nil {
onConfirm = gui.wrappedPromptConfirmationFunction(opts.handlersManageFocus, opts.handleConfirmPrompt, func() string { return gui.getConfirmationView().Buffer() })
onConfirm = gui.wrappedPromptConfirmationFunction(opts.handlersManageFocus, opts.handleConfirmPrompt, func() string { return gui.Views.Confirmation.Buffer() })
} else {
onConfirm = gui.wrappedConfirmationFunction(opts.handlersManageFocus, opts.handleConfirm)
}

View File

@ -15,32 +15,34 @@ const (
PERSISTENT_POPUP
)
type ContextKey string
const (
STATUS_CONTEXT_KEY = "status"
FILES_CONTEXT_KEY = "files"
LOCAL_BRANCHES_CONTEXT_KEY = "localBranches"
REMOTES_CONTEXT_KEY = "remotes"
REMOTE_BRANCHES_CONTEXT_KEY = "remoteBranches"
TAGS_CONTEXT_KEY = "tags"
BRANCH_COMMITS_CONTEXT_KEY = "commits"
REFLOG_COMMITS_CONTEXT_KEY = "reflogCommits"
SUB_COMMITS_CONTEXT_KEY = "subCommits"
COMMIT_FILES_CONTEXT_KEY = "commitFiles"
STASH_CONTEXT_KEY = "stash"
MAIN_NORMAL_CONTEXT_KEY = "normal"
MAIN_MERGING_CONTEXT_KEY = "merging"
MAIN_PATCH_BUILDING_CONTEXT_KEY = "patchBuilding"
MAIN_STAGING_CONTEXT_KEY = "staging"
MENU_CONTEXT_KEY = "menu"
CREDENTIALS_CONTEXT_KEY = "credentials"
CONFIRMATION_CONTEXT_KEY = "confirmation"
SEARCH_CONTEXT_KEY = "search"
COMMIT_MESSAGE_CONTEXT_KEY = "commitMessage"
SUBMODULES_CONTEXT_KEY = "submodules"
SUGGESTIONS_CONTEXT_KEY = "suggestions"
STATUS_CONTEXT_KEY ContextKey = "status"
FILES_CONTEXT_KEY = "files"
LOCAL_BRANCHES_CONTEXT_KEY = "localBranches"
REMOTES_CONTEXT_KEY = "remotes"
REMOTE_BRANCHES_CONTEXT_KEY = "remoteBranches"
TAGS_CONTEXT_KEY = "tags"
BRANCH_COMMITS_CONTEXT_KEY = "commits"
REFLOG_COMMITS_CONTEXT_KEY = "reflogCommits"
SUB_COMMITS_CONTEXT_KEY = "subCommits"
COMMIT_FILES_CONTEXT_KEY = "commitFiles"
STASH_CONTEXT_KEY = "stash"
MAIN_NORMAL_CONTEXT_KEY = "normal"
MAIN_MERGING_CONTEXT_KEY = "merging"
MAIN_PATCH_BUILDING_CONTEXT_KEY = "patchBuilding"
MAIN_STAGING_CONTEXT_KEY = "staging"
MENU_CONTEXT_KEY = "menu"
CREDENTIALS_CONTEXT_KEY = "credentials"
CONFIRMATION_CONTEXT_KEY = "confirmation"
SEARCH_CONTEXT_KEY = "search"
COMMIT_MESSAGE_CONTEXT_KEY = "commitMessage"
SUBMODULES_CONTEXT_KEY = "submodules"
SUGGESTIONS_CONTEXT_KEY = "suggestions"
)
var allContextKeys = []string{
var allContextKeys = []ContextKey{
STATUS_CONTEXT_KEY,
FILES_CONTEXT_KEY,
LOCAL_BRANCHES_CONTEXT_KEY,
@ -124,7 +126,7 @@ type Context interface {
GetViewName() string
GetWindowName() string
SetWindowName(string)
GetKey() string
GetKey() ContextKey
SetParentContext(Context)
// we return a bool here to tell us whether or not the returned value just wraps a nil
@ -138,7 +140,7 @@ type BasicContext struct {
OnRender func() error
OnGetOptionsMap func() map[string]string
Kind ContextKind
Key string
Key ContextKey
ViewName string
}
@ -192,7 +194,7 @@ func (c BasicContext) GetKind() ContextKind {
return c.Kind
}
func (c BasicContext) GetKey() string {
func (c BasicContext) GetKey() ContextKey {
return c.Key
}
@ -353,7 +355,7 @@ func (tree ContextTree) initialViewTabContextMap() map[string][]tabContext {
}
}
func (gui *Gui) currentContextKeyIgnoringPopups() string {
func (gui *Gui) currentContextKeyIgnoringPopups() ContextKey {
gui.State.ContextManager.Lock()
defer gui.State.ContextManager.Unlock()
@ -461,7 +463,10 @@ func (gui *Gui) returnFromContext() error {
func (gui *Gui) deactivateContext(c Context) error {
// if we are the kind of context that is sent to back upon deactivation, we should do that
if c.GetKind() == TEMPORARY_POPUP || c.GetKind() == PERSISTENT_POPUP || c.GetKey() == COMMIT_FILES_CONTEXT_KEY {
_, _ = gui.g.SetViewOnBottom(c.GetViewName())
view, err := gui.g.View(c.GetViewName())
if err == nil {
view.Visible = false
}
}
if err := c.HandleFocusLost(); err != nil {
@ -480,7 +485,7 @@ func (gui *Gui) postRefreshUpdate(c Context) error {
return nil
}
if v.Context != c.GetKey() {
if ContextKey(v.Context) != c.GetKey() {
return nil
}
@ -504,7 +509,7 @@ func (gui *Gui) activateContext(c Context) error {
if err != nil {
return gui.returnFromContext()
}
originalViewContextKey := v.Context
originalViewContextKey := ContextKey(v.Context)
// ensure that any other window for which this view was active is now set to the default for that window.
gui.setViewAsActiveForWindow(viewName)
@ -522,10 +527,7 @@ func (gui *Gui) activateContext(c Context) error {
return gui.returnFromContext()
}
if _, err := gui.g.SetViewOnTop(viewName); err != nil {
// if view no longer exists, pop again
return gui.returnFromContext()
}
v.Visible = true
// if the new context's view was previously displaying another context, render the new context
if originalViewContextKey != c.GetKey() {
@ -534,7 +536,7 @@ func (gui *Gui) activateContext(c Context) error {
}
}
v.Context = c.GetKey()
v.Context = string(c.GetKey())
gui.g.Cursor = v.Editable
@ -559,7 +561,7 @@ func (gui *Gui) activateContext(c Context) error {
func (gui *Gui) renderContextStack() string {
result := ""
for _, context := range gui.State.ContextManager.ContextStack {
result += context.GetKey() + "\n"
result += string(context.GetKey()) + "\n"
}
return result
}
@ -575,7 +577,18 @@ func (gui *Gui) currentContext() Context {
return gui.State.ContextManager.ContextStack[len(gui.State.ContextManager.ContextStack)-1]
}
func (gui *Gui) currentSideContext() *ListContext {
// the status panel is not yet a list context (and may never be), so this method is not
// quite the same as currentSideContext()
func (gui *Gui) currentSideListContext() *ListContext {
context := gui.currentSideContext()
listContext, ok := context.(*ListContext)
if !ok {
return nil
}
return listContext
}
func (gui *Gui) currentSideContext() Context {
gui.State.ContextManager.Lock()
defer gui.State.ContextManager.Unlock()
@ -583,7 +596,7 @@ func (gui *Gui) currentSideContext() *ListContext {
// on startup the stack can be empty so we'll return an empty string in that case
if len(stack) == 0 {
return nil
return gui.defaultSideContext()
}
// find the first context in the stack with the type of SIDE_CONTEXT
@ -591,20 +604,19 @@ func (gui *Gui) currentSideContext() *ListContext {
context := stack[len(stack)-1-i]
if context.GetKind() == SIDE_CONTEXT {
// not all side contexts are list contexts (e.g. the status panel)
listContext, ok := context.(*ListContext)
if !ok {
return nil
}
return listContext
return context
}
}
return nil
return gui.defaultSideContext()
}
func (gui *Gui) defaultSideContext() Context {
return gui.State.Contexts.Files
if gui.State.Modes.Filtering.Active() {
return gui.State.Contexts.BranchCommits
} else {
return gui.State.Contexts.Files
}
}
// remove the need to do this: always use a mapping
@ -618,7 +630,7 @@ func (gui *Gui) setInitialViewContexts() {
continue
}
view.Context = context.GetKey()
view.Context = string(context.GetKey())
}
}
@ -678,15 +690,15 @@ func (gui *Gui) onViewFocusLost(v *gocui.View, newView *gocui.View) error {
// which currently just means a context that affects both the main and secondary views
// other views can have their context changed directly but this function helps
// keep the main and secondary views in sync
func (gui *Gui) changeMainViewsContext(contextKey string) {
func (gui *Gui) changeMainViewsContext(contextKey ContextKey) {
if gui.State.MainContext == contextKey {
return
}
switch contextKey {
case MAIN_NORMAL_CONTEXT_KEY, MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY, MAIN_MERGING_CONTEXT_KEY:
gui.getMainView().Context = contextKey
gui.getSecondaryView().Context = contextKey
gui.Views.Main.Context = string(contextKey)
gui.Views.Secondary.Context = string(contextKey)
default:
panic(fmt.Sprintf("unknown context for main: %s", contextKey))
}
@ -737,7 +749,7 @@ type tabContext struct {
contexts []Context
}
func (gui *Gui) mustContextForContextKey(contextKey string) Context {
func (gui *Gui) mustContextForContextKey(contextKey ContextKey) Context {
context, ok := gui.contextForContextKey(contextKey)
if !ok {
@ -747,7 +759,7 @@ func (gui *Gui) mustContextForContextKey(contextKey string) Context {
return context
}
func (gui *Gui) contextForContextKey(contextKey string) (Context, bool) {
func (gui *Gui) contextForContextKey(contextKey ContextKey) (Context, bool) {
for _, context := range gui.allContexts() {
if context.GetKey() == contextKey {
return context, true
@ -763,7 +775,7 @@ func (gui *Gui) rerenderView(viewName string) error {
return nil
}
contextKey := v.Context
contextKey := ContextKey(v.Context)
context := gui.mustContextForContextKey(contextKey)
return context.HandleRender()
@ -782,7 +794,7 @@ func (gui *Gui) rerenderView(viewName string) error {
// }
func (gui *Gui) getSideContextSelectedItemId() string {
currentSideContext := gui.currentSideContext()
currentSideContext := gui.currentSideListContext()
if currentSideContext == nil {
return ""
}

View File

@ -40,7 +40,7 @@ func (gui *Gui) promptUserForCredential(passOrUname string) string {
}
func (gui *Gui) handleSubmitCredential() error {
credentialsView := gui.getCredentialsView()
credentialsView := gui.Views.Credentials
message := gui.trimmedContent(credentialsView)
gui.credentials <- message
gui.clearEditorView(credentialsView)

View File

@ -176,9 +176,14 @@ func (gui *Gui) GetCustomCommandKeybindings() []*Binding {
case "":
log.Fatalf("Error parsing custom command keybindings: context not provided (use context: 'global' for the global context). Key: %s, Command: %s", customCommand.Key, customCommand.Command)
default:
context, ok := gui.contextForContextKey(customCommand.Context)
context, ok := gui.contextForContextKey(ContextKey(customCommand.Context))
// stupid golang making me build an array of strings for this.
allContextKeyStrings := make([]string, len(allContextKeys))
for i := range allContextKeys {
allContextKeyStrings[i] = string(allContextKeys[i])
}
if !ok {
log.Fatalf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key, customCommand.Command, strings.Join(allContextKeys, ", "))
log.Fatalf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key, customCommand.Command, strings.Join(allContextKeyStrings, ", "))
}
// here we assume that a given context will always belong to the same view.
// Currently this is a safe bet but it's by no means guaranteed in the long term

View File

@ -14,7 +14,7 @@ func (gui *Gui) renderDiff() error {
cmd := gui.OSCommand.ExecutableFromString(
fmt.Sprintf("git diff --submodule --no-ext-diff --color %s", gui.diffStr()),
)
task := gui.createRunPtyTask(cmd)
task := NewRunPtyTask(cmd)
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{
@ -49,7 +49,7 @@ func (gui *Gui) currentDiffTerminals() []string {
}
return nil
default:
context := gui.currentSideContext()
context := gui.currentSideListContext()
if context == nil {
return nil
}

View File

@ -42,7 +42,7 @@ func (gui *Gui) getSelectedPath() string {
}
func (gui *Gui) selectFile(alreadySelected bool) error {
gui.getFilesView().FocusPoint(0, gui.State.Panels.Files.SelectedLineIdx)
gui.Views.Files.FocusPoint(0, gui.State.Panels.Files.SelectedLineIdx)
node := gui.getSelectedFileNode()
@ -50,17 +50,17 @@ func (gui *Gui) selectFile(alreadySelected bool) error {
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{
title: "",
task: gui.createRenderStringTask(gui.Tr.NoChangedFiles),
task: NewRenderStringTask(gui.Tr.NoChangedFiles),
},
})
}
if !alreadySelected {
// TODO: pull into update task interface
if err := gui.resetOrigin(gui.getMainView()); err != nil {
if err := gui.resetOrigin(gui.Views.Main); err != nil {
return err
}
if err := gui.resetOrigin(gui.getSecondaryView()); err != nil {
if err := gui.resetOrigin(gui.Views.Secondary); err != nil {
return err
}
gui.takeOverMergeConflictScrolling()
@ -75,7 +75,7 @@ func (gui *Gui) selectFile(alreadySelected bool) error {
refreshOpts := refreshMainOpts{main: &viewUpdateOpts{
title: gui.Tr.UnstagedChanges,
task: gui.createRunPtyTask(cmd),
task: NewRunPtyTask(cmd),
}}
if node.GetHasUnstagedChanges() {
@ -85,7 +85,7 @@ func (gui *Gui) selectFile(alreadySelected bool) error {
refreshOpts.secondary = &viewUpdateOpts{
title: gui.Tr.StagedChanges,
task: gui.createRunPtyTask(cmd),
task: NewRunPtyTask(cmd),
}
}
} else {
@ -105,11 +105,6 @@ func (gui *Gui) refreshFilesAndSubmodules() error {
selectedPath := gui.getSelectedPath()
filesView := gui.getFilesView()
if filesView == nil {
// if the filesView hasn't been instantiated yet we just return
return nil
}
if err := gui.refreshStateSubmoduleConfigs(); err != nil {
return err
}
@ -122,14 +117,14 @@ func (gui *Gui) refreshFilesAndSubmodules() error {
gui.Log.Error(err)
}
if gui.getFilesView().Context == FILES_CONTEXT_KEY {
if gui.Views.Files.Context == FILES_CONTEXT_KEY {
// doing this a little custom (as opposed to using gui.postRefreshUpdate) because we handle selecting the file explicitly below
if err := gui.State.Contexts.Files.HandleRender(); err != nil {
return err
}
}
if gui.currentContext().GetKey() == FILES_CONTEXT_KEY || (g.CurrentView() == gui.getMainView() && g.CurrentView().Context == MAIN_MERGING_CONTEXT_KEY) {
if gui.currentContext().GetKey() == FILES_CONTEXT_KEY || (g.CurrentView() == gui.Views.Main && g.CurrentView().Context == MAIN_MERGING_CONTEXT_KEY) {
newSelectedPath := gui.getSelectedPath()
alreadySelected := selectedPath != "" && newSelectedPath == selectedPath
if err := gui.selectFile(alreadySelected); err != nil {
@ -350,7 +345,7 @@ func (gui *Gui) handleWIPCommitPress() error {
}
_ = gui.renderStringSync("commitMessage", skipHookPreifx)
if err := gui.getCommitMessageView().SetCursor(len(skipHookPreifx), 0); err != nil {
if err := gui.Views.CommitMessage.SetCursor(len(skipHookPreifx), 0); err != nil {
return err
}
@ -389,7 +384,6 @@ func (gui *Gui) handleCommitPress() error {
return gui.promptToStageAllAndRetry(gui.handleCommitPress)
}
commitMessageView := gui.getCommitMessageView()
commitPrefixConfig := gui.commitPrefixConfigForRepo()
if commitPrefixConfig != nil {
prefixPattern := commitPrefixConfig.Pattern
@ -400,7 +394,7 @@ func (gui *Gui) handleCommitPress() error {
}
prefix := rgx.ReplaceAllString(gui.getCheckedOutBranch().Name, prefixReplace)
gui.renderString("commitMessage", prefix)
if err := commitMessageView.SetCursor(len(prefix), 0); err != nil {
if err := gui.Views.CommitMessage.SetCursor(len(prefix), 0); err != nil {
return err
}
}
@ -862,7 +856,7 @@ func (gui *Gui) handleToggleFileTreeView() error {
}
}
if gui.getFilesView().Context == FILES_CONTEXT_KEY {
if gui.Views.Files.Context == FILES_CONTEXT_KEY {
if err := gui.State.Contexts.Files.HandleRender(); err != nil {
return err
}

View File

@ -5,6 +5,7 @@ import (
"math"
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/utils"
)
@ -59,30 +60,22 @@ func (gui *Gui) prevScreenMode() error {
return gui.rerenderViewsWithScreenModeDependentContent()
}
func (gui *Gui) scrollUpView(viewName string) error {
mainView, err := gui.g.View(viewName)
if err != nil {
return nil
}
ox, oy := mainView.Origin()
func (gui *Gui) scrollUpView(view *gocui.View) error {
ox, oy := view.Origin()
newOy := int(math.Max(0, float64(oy-gui.Config.GetUserConfig().Gui.ScrollHeight)))
return mainView.SetOrigin(ox, newOy)
return view.SetOrigin(ox, newOy)
}
func (gui *Gui) scrollDownView(viewName string) error {
mainView, err := gui.g.View(viewName)
if err != nil {
return nil
}
ox, oy := mainView.Origin()
func (gui *Gui) scrollDownView(view *gocui.View) error {
ox, oy := view.Origin()
y := oy
canScrollPastBottom := gui.Config.GetUserConfig().Gui.ScrollPastBottom
if !canScrollPastBottom {
_, sy := mainView.Size()
_, sy := view.Size()
y += sy
}
scrollHeight := gui.Config.GetUserConfig().Gui.ScrollHeight
scrollableLines := mainView.ViewLinesHeight() - y
scrollableLines := view.ViewLinesHeight() - y
if scrollableLines > 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
@ -95,12 +88,12 @@ func (gui *Gui) scrollDownView(viewName string) error {
scrollHeight = scrollableLines - margin
}
if oy+scrollHeight >= 0 {
if err := mainView.SetOrigin(ox, oy+scrollHeight); err != nil {
if err := view.SetOrigin(ox, oy+scrollHeight); err != nil {
return err
}
}
}
if manager, ok := gui.viewBufferManagerMap[viewName]; ok {
if manager, ok := gui.viewBufferManagerMap[view.Name()]; ok {
manager.ReadLines(scrollHeight)
}
return nil
@ -111,7 +104,7 @@ func (gui *Gui) scrollUpMain() error {
gui.State.Panels.Merging.UserScrolling = true
}
return gui.scrollUpView("main")
return gui.scrollUpView(gui.Views.Main)
}
func (gui *Gui) scrollDownMain() error {
@ -119,33 +112,31 @@ func (gui *Gui) scrollDownMain() error {
gui.State.Panels.Merging.UserScrolling = true
}
return gui.scrollDownView("main")
return gui.scrollDownView(gui.Views.Main)
}
func (gui *Gui) scrollUpSecondary() error {
return gui.scrollUpView("secondary")
return gui.scrollUpView(gui.Views.Secondary)
}
func (gui *Gui) scrollDownSecondary() error {
return gui.scrollDownView("secondary")
return gui.scrollDownView(gui.Views.Secondary)
}
func (gui *Gui) scrollUpConfirmationPanel() error {
view := gui.getConfirmationView()
if view != nil || view.Editable {
if gui.Views.Confirmation.Editable {
return nil
}
return gui.scrollUpView("confirmation")
return gui.scrollUpView(gui.Views.Confirmation)
}
func (gui *Gui) scrollDownConfirmationPanel() error {
view := gui.getConfirmationView()
if view != nil || view.Editable {
if gui.Views.Confirmation.Editable {
return nil
}
return gui.scrollDownView("confirmation")
return gui.scrollDownView(gui.Views.Confirmation)
}
func (gui *Gui) handleRefresh() error {
@ -157,16 +148,14 @@ func (gui *Gui) handleMouseDownMain() error {
return nil
}
view := gui.getMainView()
switch gui.g.CurrentView().Name() {
case "files":
// set filename, set primary/secondary selected, set line number, then switch context
// I'll need to know it was changed though.
// Could I pass something along to the context change?
return gui.enterFile(false, view.SelectedLineIdx())
return gui.enterFile(false, gui.Views.Main.SelectedLineIdx())
case "commitFiles":
return gui.enterCommitFile(view.SelectedLineIdx())
return gui.enterCommitFile(gui.Views.Main.SelectedLineIdx())
}
return nil
@ -177,11 +166,9 @@ func (gui *Gui) handleMouseDownSecondary() error {
return nil
}
view := gui.getSecondaryView()
switch gui.g.CurrentView().Name() {
case "files":
return gui.enterFile(true, view.SelectedLineIdx())
return gui.enterFile(true, gui.Views.Secondary.SelectedLineIdx())
}
return nil
@ -192,7 +179,7 @@ func (gui *Gui) handleInfoClick() error {
return nil
}
view := gui.getInformationView()
view := gui.Views.Information
cx, _ := view.Cursor()
width, _ := view.Size()

View File

@ -106,6 +106,8 @@ type Gui struct {
// this tells us whether our views have been initially set up
ViewsSetup bool
Views Views
}
type RecordedEvent struct {
@ -232,6 +234,28 @@ type panelStates struct {
Suggestions *suggestionsPanelState
}
type Views struct {
Status *gocui.View
Files *gocui.View
Branches *gocui.View
Commits *gocui.View
Stash *gocui.View
Main *gocui.View
Secondary *gocui.View
Options *gocui.View
Confirmation *gocui.View
Menu *gocui.View
Credentials *gocui.View
CommitMessage *gocui.View
CommitFiles *gocui.View
Information *gocui.View
AppStatus *gocui.View
Search *gocui.View
SearchPrefix *gocui.View
Limit *gocui.View
Suggestions *gocui.View
}
type searchingState struct {
view *gocui.View
isSearching bool
@ -260,7 +284,7 @@ type CherryPicking struct {
CherryPickedCommits []*models.Commit
// we only allow cherry picking from one context at a time, so you can't copy a commit from the local commits context and then also copy a commit in the reflog context
ContextKey string
ContextKey ContextKey
}
func (m *CherryPicking) Active() bool {
@ -306,8 +330,8 @@ type guiState struct {
MenuItems []*menuItem
Updating bool
Panels *panelStates
MainContext string // used to keep the main and secondary views' contexts in sync
SplitMainPanel bool
MainContext ContextKey // used to keep the main and secondary views' contexts in sync
RetainOriginalDir bool
IsRefreshingFiles bool
Searching searchingState

View File

@ -625,21 +625,21 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "branches",
Contexts: []string{TAGS_CONTEXT_KEY},
Key: gui.getKey(config.Universal.Select),
Handler: gui.handleCheckoutTag,
Handler: gui.withSelectedTag(gui.handleCheckoutTag),
Description: gui.Tr.LcCheckout,
},
{
ViewName: "branches",
Contexts: []string{TAGS_CONTEXT_KEY},
Key: gui.getKey(config.Universal.Remove),
Handler: gui.handleDeleteTag,
Handler: gui.withSelectedTag(gui.handleDeleteTag),
Description: gui.Tr.LcDeleteTag,
},
{
ViewName: "branches",
Contexts: []string{TAGS_CONTEXT_KEY},
Key: gui.getKey(config.Branches.PushTag),
Handler: gui.handlePushTag,
Handler: gui.withSelectedTag(gui.handlePushTag),
Description: gui.Tr.LcPushTag,
},
{
@ -653,7 +653,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "branches",
Contexts: []string{TAGS_CONTEXT_KEY},
Key: gui.getKey(config.Commits.ViewResetOptions),
Handler: gui.handleCreateResetToTagMenu,
Handler: gui.withSelectedTag(gui.handleCreateResetToTagMenu),
Description: gui.Tr.LcViewResetOptions,
OpensMenu: true,
},

View File

@ -31,29 +31,22 @@ func (gui *Gui) layout(g *gocui.Gui) error {
minimumHeight := 9
minimumWidth := 10
if height < minimumHeight || width < minimumWidth {
v, err := g.SetView("limit", 0, 0, width-1, height-1, 0)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
v.Title = gui.Tr.NotEnoughSpace
v.Wrap = true
_, _ = g.SetViewOnTop("limit")
var err error
gui.Views.Limit, err = g.SetView("limit", 0, 0, width-1, height-1, 0)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
return nil
gui.Views.Limit.Title = gui.Tr.NotEnoughSpace
gui.Views.Limit.Wrap = true
}
gui.Views.Limit.Visible = height < minimumHeight || width < minimumWidth
informationStr := gui.informationStr()
appStatus := gui.statusManager.getStatusString()
viewDimensions := gui.getWindowDimensions(informationStr, appStatus)
_, _ = g.SetViewOnBottom("limit")
_ = g.DeleteView("limit")
textColor := theme.GocuiDefaultTextColor
// reading more lines into main view buffers upon resize
prevMainView, err := gui.g.View("main")
if err == nil {
@ -79,17 +72,17 @@ func (gui *Gui) layout(g *gocui.Gui) error {
// to render content as soon as it appears, because lazyloaded content (via a pty task)
// cares about the size of the view.
view, err := g.SetView(viewName, 0, 0, width, height, 0)
if err != nil {
return view, err
if view != nil {
view.Visible = false
}
return g.SetViewOnBottom(viewName)
return view, err
}
frameOffset := 1
if frame {
frameOffset = 0
}
return g.SetView(
view, err := g.SetView(
viewName,
dimensionsObj.X0-frameOffset,
dimensionsObj.Y0-frameOffset,
@ -97,172 +90,150 @@ func (gui *Gui) layout(g *gocui.Gui) error {
dimensionsObj.Y1+frameOffset,
0,
)
if view != nil {
view.Visible = true
}
return view, err
}
v, err := setViewFromDimensions("main", "main", true)
gui.Views.Main, err = setViewFromDimensions("main", "main", true)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
v.Title = gui.Tr.DiffTitle
v.Wrap = true
v.FgColor = textColor
v.IgnoreCarriageReturns = true
gui.Views.Main.Title = gui.Tr.DiffTitle
gui.Views.Main.Wrap = true
gui.Views.Main.FgColor = theme.GocuiDefaultTextColor
gui.Views.Main.IgnoreCarriageReturns = true
}
secondaryView, err := setViewFromDimensions("secondary", "secondary", true)
gui.Views.Secondary, err = setViewFromDimensions("secondary", "secondary", true)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
secondaryView.Title = gui.Tr.DiffTitle
secondaryView.Wrap = true
secondaryView.FgColor = textColor
secondaryView.IgnoreCarriageReturns = true
gui.Views.Secondary.Title = gui.Tr.DiffTitle
gui.Views.Secondary.Wrap = true
gui.Views.Secondary.FgColor = theme.GocuiDefaultTextColor
gui.Views.Secondary.IgnoreCarriageReturns = true
}
hiddenViewOffset := 9999
if v, err := setViewFromDimensions("status", "status", true); err != nil {
if gui.Views.Status, err = setViewFromDimensions("status", "status", true); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
v.Title = gui.Tr.StatusTitle
v.FgColor = textColor
gui.Views.Status.Title = gui.Tr.StatusTitle
gui.Views.Status.FgColor = theme.GocuiDefaultTextColor
}
filesView, err := setViewFromDimensions("files", "files", true)
gui.Views.Files, err = setViewFromDimensions("files", "files", true)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
filesView.Highlight = true
filesView.Title = gui.Tr.FilesTitle
filesView.FgColor = textColor
filesView.ContainsList = true
gui.Views.Files.Highlight = true
gui.Views.Files.Title = gui.Tr.FilesTitle
gui.Views.Files.FgColor = theme.GocuiDefaultTextColor
gui.Views.Files.ContainsList = true
}
branchesView, err := setViewFromDimensions("branches", "branches", true)
gui.Views.Branches, err = setViewFromDimensions("branches", "branches", true)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
branchesView.Title = gui.Tr.BranchesTitle
branchesView.FgColor = textColor
branchesView.ContainsList = true
gui.Views.Branches.Title = gui.Tr.BranchesTitle
gui.Views.Branches.FgColor = theme.GocuiDefaultTextColor
gui.Views.Branches.ContainsList = true
}
commitFilesView, err := setViewFromDimensions("commitFiles", gui.State.Contexts.CommitFiles.GetWindowName(), true)
gui.Views.CommitFiles, err = setViewFromDimensions("commitFiles", gui.State.Contexts.CommitFiles.GetWindowName(), true)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
commitFilesView.Title = gui.Tr.CommitFiles
commitFilesView.FgColor = textColor
commitFilesView.ContainsList = true
_, _ = gui.g.SetViewOnBottom("commitFiles")
gui.Views.CommitFiles.Title = gui.Tr.CommitFiles
gui.Views.CommitFiles.FgColor = theme.GocuiDefaultTextColor
gui.Views.CommitFiles.ContainsList = true
}
// if the commit files view is the view to be displayed for its window, we'll display it
gui.Views.CommitFiles.Visible = gui.getViewNameForWindow(gui.State.Contexts.CommitFiles.GetWindowName()) == "commitFiles"
commitsView, err := setViewFromDimensions("commits", "commits", true)
gui.Views.Commits, err = setViewFromDimensions("commits", "commits", true)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
commitsView.Title = gui.Tr.CommitsTitle
commitsView.FgColor = textColor
commitsView.ContainsList = true
gui.Views.Commits.Title = gui.Tr.CommitsTitle
gui.Views.Commits.FgColor = theme.GocuiDefaultTextColor
gui.Views.Commits.ContainsList = true
}
stashView, err := setViewFromDimensions("stash", "stash", true)
gui.Views.Stash, err = setViewFromDimensions("stash", "stash", true)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
stashView.Title = gui.Tr.StashTitle
stashView.FgColor = textColor
stashView.ContainsList = true
gui.Views.Stash.Title = gui.Tr.StashTitle
gui.Views.Stash.FgColor = theme.GocuiDefaultTextColor
gui.Views.Stash.ContainsList = true
}
if gui.getCommitMessageView() == nil {
// doesn't matter where this view starts because it will be hidden
if commitMessageView, err := g.SetView("commitMessage", hiddenViewOffset, hiddenViewOffset, hiddenViewOffset+10, hiddenViewOffset+10, 0); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
_, _ = g.SetViewOnBottom("commitMessage")
commitMessageView.Title = gui.Tr.CommitMessage
commitMessageView.FgColor = textColor
commitMessageView.Editable = true
commitMessageView.Editor = gocui.EditorFunc(gui.commitMessageEditor)
}
}
if check, _ := g.View("credentials"); check == nil {
// doesn't matter where this view starts because it will be hidden
if credentialsView, err := g.SetView("credentials", hiddenViewOffset, hiddenViewOffset, hiddenViewOffset+10, hiddenViewOffset+10, 0); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
_, _ = g.SetViewOnBottom("credentials")
credentialsView.Title = gui.Tr.CredentialsUsername
credentialsView.FgColor = textColor
credentialsView.Editable = true
}
}
if v, err := setViewFromDimensions("options", "options", false); err != nil {
if gui.Views.Options, err = setViewFromDimensions("options", "options", false); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
v.Frame = false
v.FgColor = theme.OptionsColor
gui.Views.Options.Frame = false
gui.Views.Options.FgColor = theme.OptionsColor
}
// this view takes up one character. Its only purpose is to show the slash when searching
if searchPrefixView, err := setViewFromDimensions("searchPrefix", "searchPrefix", false); err != nil {
if gui.Views.SearchPrefix, err = setViewFromDimensions("searchPrefix", "searchPrefix", false); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
searchPrefixView.BgColor = gocui.ColorDefault
searchPrefixView.FgColor = gocui.ColorGreen
searchPrefixView.Frame = false
gui.setViewContent(searchPrefixView, SEARCH_PREFIX)
gui.Views.SearchPrefix.BgColor = gocui.ColorDefault
gui.Views.SearchPrefix.FgColor = gocui.ColorGreen
gui.Views.SearchPrefix.Frame = false
gui.setViewContent(gui.Views.SearchPrefix, SEARCH_PREFIX)
}
if searchView, err := setViewFromDimensions("search", "search", false); err != nil {
if gui.Views.Search, err = setViewFromDimensions("search", "search", false); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
searchView.BgColor = gocui.ColorDefault
searchView.FgColor = gocui.ColorGreen
searchView.Frame = false
searchView.Editable = true
gui.Views.Search.BgColor = gocui.ColorDefault
gui.Views.Search.FgColor = gocui.ColorGreen
gui.Views.Search.Frame = false
gui.Views.Search.Editable = true
}
if appStatusView, err := setViewFromDimensions("appStatus", "appStatus", false); err != nil {
if gui.Views.AppStatus, err = setViewFromDimensions("appStatus", "appStatus", false); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
appStatusView.BgColor = gocui.ColorDefault
appStatusView.FgColor = gocui.ColorCyan
appStatusView.Frame = false
_, _ = g.SetViewOnBottom("appStatus")
gui.Views.AppStatus.BgColor = gocui.ColorDefault
gui.Views.AppStatus.FgColor = gocui.ColorCyan
gui.Views.AppStatus.Frame = false
gui.Views.AppStatus.Visible = false
}
informationView, err := setViewFromDimensions("information", "information", false)
gui.Views.Information, err = setViewFromDimensions("information", "information", false)
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
informationView.BgColor = gocui.ColorDefault
informationView.FgColor = gocui.ColorGreen
informationView.Frame = false
gui.Views.Information.BgColor = gocui.ColorDefault
gui.Views.Information.FgColor = gocui.ColorGreen
gui.Views.Information.Frame = false
gui.renderString("information", INFO_SECTION_PADDING+informationStr)
}
if gui.State.OldInformation != informationStr {
gui.setViewContent(informationView, informationStr)
gui.setViewContent(gui.Views.Information, informationStr)
gui.State.OldInformation = informationStr
}
@ -289,7 +260,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
// ignore contexts whose view is owned by another context right now
if view.Context != listContext.GetKey() {
if ContextKey(view.Context) != listContext.GetKey() {
continue
}
@ -302,9 +273,9 @@ func (gui *Gui) layout(g *gocui.Gui) error {
view.SetOnSelectItem(gui.onSelectItemWrapper(listContext.onSearchSelect))
}
gui.getMainView().SetOnSelectItem(gui.onSelectItemWrapper(gui.handlelineByLineNavigateTo))
gui.Views.Main.SetOnSelectItem(gui.onSelectItemWrapper(gui.handlelineByLineNavigateTo))
mainViewWidth, mainViewHeight := gui.getMainView().Size()
mainViewWidth, mainViewHeight := gui.Views.Main.Size()
if mainViewWidth != gui.State.PrevMainWidth || mainViewHeight != gui.State.PrevMainHeight {
gui.State.PrevMainWidth = mainViewWidth
gui.State.PrevMainHeight = mainViewHeight
@ -320,28 +291,24 @@ func (gui *Gui) layout(g *gocui.Gui) error {
return gui.resizeCurrentPopupPanel()
}
func (gui *Gui) setHiddenView(viewName string) (*gocui.View, error) {
// arbitrarily giving the view enough size so that we don't get an error, but
// it's expected that the view will be given the correct size before being shown
return gui.g.SetView(viewName, 0, 0, 10, 10, 0)
}
func (gui *Gui) onInitialViewsCreationForRepo() error {
gui.setInitialViewContexts()
// hide any popup views. This only applies when we've just switched repos
for _, viewName := range gui.popupViewNames() {
_, _ = gui.g.SetViewOnBottom(viewName)
}
// the status panel is not actually a list context at the moment, so it is excluded
// here. Arguably that's quite convenient because it means we're back to starting
// in the files panel when landing in a new repo, but when returning from a submodule
// we'll be back in the submodules context. This still seems awkward though, and it's
// definitely going to break when (if) we make the status context a list context
initialContext := gui.currentSideContext()
if initialContext == nil {
if gui.State.Modes.Filtering.Active() {
initialContext = gui.State.Contexts.BranchCommits
} else {
initialContext = gui.State.Contexts.Files
view, err := gui.g.View(viewName)
if err == nil {
view.Visible = false
}
}
initialContext := gui.currentSideContext()
if err := gui.pushContext(initialContext); err != nil {
return err
}
@ -350,6 +317,49 @@ func (gui *Gui) onInitialViewsCreationForRepo() error {
}
func (gui *Gui) onInitialViewsCreation() error {
// creating some views which are hidden at the start but we need to exist so that we can set an initial ordering
if err := gui.createHiddenViews(); err != nil {
return err
}
// now we order the views (in order of bottom first)
layerOneViews := []*gocui.View{
// first layer. Ordering within this layer does not matter because there are
// no overlapping views
gui.Views.Status,
gui.Views.Files,
gui.Views.Branches,
gui.Views.Commits,
gui.Views.Stash,
gui.Views.CommitFiles,
gui.Views.Main,
gui.Views.Secondary,
// bottom line
gui.Views.Options,
gui.Views.AppStatus,
gui.Views.Information,
gui.Views.Search,
gui.Views.SearchPrefix,
// popups. Ordering within this layer does not matter because there should
// only be one popup shown at a time
gui.Views.CommitMessage,
gui.Views.Credentials,
gui.Views.Menu,
gui.Views.Confirmation,
gui.Views.Suggestions,
// this guy will cover everything else when it appears
gui.Views.Limit,
}
for _, view := range layerOneViews {
if _, err := gui.g.SetViewOnTop(view.Name()); err != nil {
return err
}
}
gui.g.Mutexes.ViewsMutex.Lock()
// add tabs to views
for _, view := range gui.g.Views() {
@ -378,3 +388,58 @@ func (gui *Gui) onInitialViewsCreation() error {
return nil
}
func (gui *Gui) createHiddenViews() error {
// doesn't matter where this view starts because it will be hidden
var err error
if gui.Views.CommitMessage, err = gui.setHiddenView("commitMessage"); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
gui.Views.CommitMessage.Visible = false
gui.Views.CommitMessage.Title = gui.Tr.CommitMessage
gui.Views.CommitMessage.FgColor = theme.GocuiDefaultTextColor
gui.Views.CommitMessage.Editable = true
gui.Views.CommitMessage.Editor = gocui.EditorFunc(gui.commitMessageEditor)
}
// doesn't matter where this view starts because it will be hidden
if gui.Views.Credentials, err = gui.setHiddenView("credentials"); err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
gui.Views.Credentials.Visible = false
gui.Views.Credentials.Title = gui.Tr.CredentialsUsername
gui.Views.Credentials.FgColor = theme.GocuiDefaultTextColor
gui.Views.Credentials.Editable = true
}
// not worrying about setting attributes because that will be done when the view is actually shown
gui.Views.Confirmation, err = gui.setHiddenView("confirmation")
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
gui.Views.Confirmation.Visible = false
}
// not worrying about setting attributes because that will be done when the view is actually shown
gui.Views.Suggestions, err = gui.setHiddenView("suggestions")
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
gui.Views.Suggestions.Visible = false
}
// not worrying about setting attributes because that will be done when the view is actually shown
gui.Views.Menu, err = gui.setHiddenView("menu")
if err != nil {
if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
return err
}
gui.Views.Menu.Visible = false
}
return nil
}

View File

@ -82,9 +82,8 @@ func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, second
return false, err
}
secondaryView := gui.getSecondaryView()
secondaryView.Highlight = true
secondaryView.Wrap = false
gui.Views.Secondary.Highlight = true
gui.Views.Secondary.Wrap = false
secondaryPatchParser, err := patch.NewPatchParser(gui.Log, secondaryDiff)
if err != nil {
@ -92,7 +91,7 @@ func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, second
}
gui.g.Update(func(*gocui.Gui) error {
gui.setViewContent(gui.getSecondaryView(), secondaryPatchParser.Render(-1, -1, nil))
gui.setViewContent(gui.Views.Secondary, secondaryPatchParser.Render(-1, -1, nil))
return nil
})
@ -184,7 +183,7 @@ func (gui *Gui) handleLBLMouseDown() error {
return nil
}
newSelectedLineIdx := gui.getMainView().SelectedLineIdx()
newSelectedLineIdx := gui.Views.Main.SelectedLineIdx()
state.FirstLineIdx = newSelectedLineIdx
state.LastLineIdx = newSelectedLineIdx
@ -200,7 +199,7 @@ func (gui *Gui) handleMouseDrag() error {
return nil
}
return gui.LBLSelectLine(gui.getMainView().SelectedLineIdx(), state)
return gui.LBLSelectLine(gui.Views.Main.SelectedLineIdx(), state)
})
}
@ -248,12 +247,11 @@ func (gui *Gui) refreshMainViewForLineByLine(state *lBlPanelState) error {
}
colorDiff := state.PatchParser.Render(state.FirstLineIdx, state.LastLineIdx, includedLineIndices)
mainView := gui.getMainView()
mainView.Highlight = true
mainView.Wrap = false
gui.Views.Main.Highlight = true
gui.Views.Main.Wrap = false
gui.g.Update(func(*gocui.Gui) error {
gui.setViewContent(gui.getMainView(), colorDiff)
gui.setViewContent(gui.Views.Main, colorDiff)
return nil
})
@ -263,7 +261,7 @@ func (gui *Gui) refreshMainViewForLineByLine(state *lBlPanelState) error {
// focusSelection works out the best focus for the staging panel given the
// selected line and size of the hunk
func (gui *Gui) focusSelection(includeCurrentHunk bool, state *lBlPanelState) error {
stagingView := gui.getMainView()
stagingView := gui.Views.Main
_, viewHeight := stagingView.Size()
bufferHeight := viewHeight - 1
@ -367,7 +365,7 @@ func (gui *Gui) handleOpenFileAtLine() error {
func (gui *Gui) handleLineByLineNextPage() error {
return gui.withLBLActiveCheck(func(state *lBlPanelState) error {
newSelectedLineIdx := state.SelectedLineIdx + gui.pageDelta(gui.getMainView())
newSelectedLineIdx := state.SelectedLineIdx + gui.pageDelta(gui.Views.Main)
return gui.lineByLineNavigateTo(newSelectedLineIdx, state)
})
@ -375,7 +373,7 @@ func (gui *Gui) handleLineByLineNextPage() error {
func (gui *Gui) handleLineByLinePrevPage() error {
return gui.withLBLActiveCheck(func(state *lBlPanelState) error {
newSelectedLineIdx := state.SelectedLineIdx - gui.pageDelta(gui.getMainView())
newSelectedLineIdx := state.SelectedLineIdx - gui.pageDelta(gui.Views.Main)
return gui.lineByLineNavigateTo(newSelectedLineIdx, state)
})

View File

@ -9,7 +9,7 @@ import (
type ListContext struct {
ViewName string
ContextKey string
ContextKey ContextKey
GetItemsLength func() int
GetDisplayStrings func() [][]string
OnFocus func() error
@ -103,7 +103,7 @@ func (lc *ListContext) OnRender() error {
return nil
}
func (lc *ListContext) GetKey() string {
func (lc *ListContext) GetKey() ContextKey {
return lc.ContextKey
}
@ -136,10 +136,10 @@ func (lc *ListContext) HandleFocus() error {
view.FocusPoint(0, lc.GetPanelState().GetSelectedLineIdx())
if lc.ResetMainViewOriginOnFocus {
if err := lc.Gui.resetOrigin(lc.Gui.getMainView()); err != nil {
if err := lc.Gui.resetOrigin(lc.Gui.Views.Main); err != nil {
return err
}
if err := lc.Gui.resetOrigin(lc.Gui.getSecondaryView()); err != nil {
if err := lc.Gui.resetOrigin(lc.Gui.Views.Secondary); err != nil {
return err
}
}
@ -257,7 +257,7 @@ func (gui *Gui) menuListContext() *ListContext {
return &ListContext{
ViewName: "menu",
ContextKey: "menu",
GetItemsLength: func() int { return gui.getMenuView().LinesHeight() },
GetItemsLength: func() int { return gui.Views.Menu.LinesHeight() },
GetPanelState: func() IListPanelState { return gui.State.Panels.Menu },
OnFocus: gui.handleMenuSelect,
OnClickSelectedItem: gui.onMenuPress,
@ -556,16 +556,16 @@ func (gui *Gui) getListContextKeyBindings() []*Binding {
listContext := listContext
bindings = append(bindings, []*Binding{
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gui.getKey(keybindingConfig.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: listContext.handlePrevLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gui.getKey(keybindingConfig.Universal.PrevItem), Modifier: gocui.ModNone, Handler: listContext.handlePrevLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: listContext.handlePrevLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gui.getKey(keybindingConfig.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: listContext.handleNextLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gui.getKey(keybindingConfig.Universal.NextItem), Modifier: gocui.ModNone, Handler: listContext.handleNextLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gui.getKey(keybindingConfig.Universal.PrevPage), Modifier: gocui.ModNone, Handler: listContext.handlePrevPage, Description: gui.Tr.LcPrevPage},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gui.getKey(keybindingConfig.Universal.NextPage), Modifier: gocui.ModNone, Handler: listContext.handleNextPage, Description: gui.Tr.LcNextPage},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gui.getKey(keybindingConfig.Universal.GotoTop), Modifier: gocui.ModNone, Handler: listContext.handleGotoTop, Description: gui.Tr.LcGotoTop},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{listContext.ContextKey}, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: listContext.handleNextLine},
{ViewName: listContext.ViewName, Contexts: []string{listContext.ContextKey}, Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: listContext.handleClick},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gui.getKey(keybindingConfig.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: listContext.handlePrevLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gui.getKey(keybindingConfig.Universal.PrevItem), Modifier: gocui.ModNone, Handler: listContext.handlePrevLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: listContext.handlePrevLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gui.getKey(keybindingConfig.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: listContext.handleNextLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gui.getKey(keybindingConfig.Universal.NextItem), Modifier: gocui.ModNone, Handler: listContext.handleNextLine},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gui.getKey(keybindingConfig.Universal.PrevPage), Modifier: gocui.ModNone, Handler: listContext.handlePrevPage, Description: gui.Tr.LcPrevPage},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gui.getKey(keybindingConfig.Universal.NextPage), Modifier: gocui.ModNone, Handler: listContext.handleNextPage, Description: gui.Tr.LcNextPage},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gui.getKey(keybindingConfig.Universal.GotoTop), Modifier: gocui.ModNone, Handler: listContext.handleGotoTop, Description: gui.Tr.LcGotoTop},
{ViewName: listContext.ViewName, Tag: "navigation", Contexts: []string{string(listContext.ContextKey)}, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: listContext.handleNextLine},
{ViewName: listContext.ViewName, Contexts: []string{string(listContext.ContextKey)}, Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: listContext.handleClick},
}...)
// the commits panel needs to lazyload things so it has a couple of its own handlers
@ -579,7 +579,7 @@ func (gui *Gui) getListContextKeyBindings() []*Binding {
bindings = append(bindings, []*Binding{
{
ViewName: listContext.ViewName,
Contexts: []string{listContext.ContextKey},
Contexts: []string{string(listContext.ContextKey)},
Key: gui.getKey(keybindingConfig.Universal.StartSearch),
Handler: func() error { return openSearchHandler(listContext.ViewName) },
Description: gui.Tr.LcStartSearch,
@ -587,7 +587,7 @@ func (gui *Gui) getListContextKeyBindings() []*Binding {
},
{
ViewName: listContext.ViewName,
Contexts: []string{listContext.ContextKey},
Contexts: []string{string(listContext.ContextKey)},
Key: gui.getKey(keybindingConfig.Universal.GotoBottom),
Handler: gotoBottomHandler,
Description: gui.Tr.LcGotoBottom,

View File

@ -1,6 +1,10 @@
package gui
import "os/exec"
import (
"os/exec"
"github.com/jesseduffield/gocui"
)
type viewUpdateOpts struct {
title string
@ -42,7 +46,7 @@ func (t *renderStringTask) GetKind() TaskKind {
return RENDER_STRING
}
func (gui *Gui) createRenderStringTask(str string) *renderStringTask {
func NewRenderStringTask(str string) *renderStringTask {
return &renderStringTask{str: str}
}
@ -54,7 +58,7 @@ func (t *renderStringWithoutScrollTask) GetKind() TaskKind {
return RENDER_STRING_WITHOUT_SCROLL
}
func (gui *Gui) createRenderStringWithoutScrollTask(str string) *renderStringWithoutScrollTask {
func NewRenderStringWithoutScrollTask(str string) *renderStringWithoutScrollTask {
return &renderStringWithoutScrollTask{str: str}
}
@ -67,11 +71,11 @@ func (t *runCommandTask) GetKind() TaskKind {
return RUN_COMMAND
}
func (gui *Gui) createRunCommandTask(cmd *exec.Cmd) *runCommandTask {
func NewRunCommandTask(cmd *exec.Cmd) *runCommandTask {
return &runCommandTask{cmd: cmd}
}
func (gui *Gui) createRunCommandTaskWithPrefix(cmd *exec.Cmd, prefix string) *runCommandTask {
func NewRunCommandTaskWithPrefix(cmd *exec.Cmd, prefix string) *runCommandTask {
return &runCommandTask{cmd: cmd, prefix: prefix}
}
@ -84,7 +88,7 @@ func (t *runPtyTask) GetKind() TaskKind {
return RUN_PTY
}
func (gui *Gui) createRunPtyTask(cmd *exec.Cmd) *runPtyTask {
func NewRunPtyTask(cmd *exec.Cmd) *runPtyTask {
return &runPtyTask{cmd: cmd}
}
@ -134,18 +138,12 @@ func (gui *Gui) runTaskForView(viewName string, task updateTask) error {
return nil
}
func (gui *Gui) refreshMainView(opts *viewUpdateOpts, viewName string) error {
view, err := gui.g.View(viewName)
if err != nil {
gui.Log.Error(err)
return nil
}
func (gui *Gui) refreshMainView(opts *viewUpdateOpts, view *gocui.View) error {
view.Title = opts.title
view.Wrap = !opts.noWrap
view.Highlight = opts.highlight
if err := gui.runTaskForView(viewName, opts.task); err != nil {
if err := gui.runTaskForView(view.Name(), opts.task); err != nil {
gui.Log.Error(err)
return nil
}
@ -155,19 +153,19 @@ func (gui *Gui) refreshMainView(opts *viewUpdateOpts, viewName string) error {
func (gui *Gui) refreshMainViews(opts refreshMainOpts) error {
if opts.main != nil {
if err := gui.refreshMainView(opts.main, "main"); err != nil {
if err := gui.refreshMainView(opts.main, gui.Views.Main); err != nil {
return err
}
}
if opts.secondary != nil {
if err := gui.refreshMainView(opts.secondary, gui.Views.Secondary); err != nil {
return err
}
}
gui.splitMainPanel(opts.secondary != nil)
if opts.secondary != nil {
if err := gui.refreshMainView(opts.secondary, "secondary"); err != nil {
return err
}
}
return nil
}
@ -176,7 +174,7 @@ func (gui *Gui) splitMainPanel(splitMainPanel bool) {
// no need to set view on bottom when splitMainPanel is false: it will have zero size anyway thanks to our view arrangement code.
if splitMainPanel {
_, _ = gui.g.SetViewOnTop("secondary")
gui.Views.Secondary.Visible = false
}
}

View File

@ -43,7 +43,6 @@ func (gui *Gui) getMenuOptions() map[string]string {
}
func (gui *Gui) handleMenuClose() error {
_ = gui.g.DeleteView("menu")
return gui.returnFromContext()
}

View File

@ -179,7 +179,7 @@ func (gui *Gui) refreshMergePanel() error {
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{
title: "",
task: gui.createRenderStringTask(err.Error()),
task: NewRenderStringTask(err.Error()),
},
})
}
@ -203,7 +203,7 @@ func (gui *Gui) refreshMergePanel() error {
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{
title: gui.Tr.MergeConflictsTitle,
task: gui.createRenderStringWithoutScrollTask(content),
task: NewRenderStringWithoutScrollTask(content),
noWrap: true,
},
})
@ -236,7 +236,8 @@ func (gui *Gui) scrollToConflict() error {
if len(panelState.Conflicts) == 0 {
return nil
}
mergingView := gui.getMainView()
mergingView := gui.Views.Main
conflict := panelState.Conflicts[panelState.ConflictIndex]
ox, _ := mergingView.Origin()
_, height := mergingView.Size()
@ -269,7 +270,7 @@ func (gui *Gui) handleEscapeMerge() error {
}
// it's possible this method won't be called from the merging view so we need to
// ensure we only 'return' focus if we already have it
if gui.g.CurrentView() == gui.getMainView() {
if gui.g.CurrentView() == gui.Views.Main {
return gui.pushContext(gui.State.Contexts.Files)
}
return nil

View File

@ -22,10 +22,8 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int, state *lBlPanelSt
return gui.handleEscapePatchBuildingPanel()
}
gui.splitMainPanel(true)
gui.getMainView().Title = "Patch"
gui.getSecondaryView().Title = "Custom Patch"
gui.Views.Main.Title = "Patch"
gui.Views.Secondary.Title = "Custom Patch"
// get diff from commit file that's currently selected
node := gui.getSelectedCommitFileNode()
@ -125,7 +123,7 @@ func (gui *Gui) secondaryPatchPanelUpdateOpts() *viewUpdateOpts {
title: "Custom Patch",
noWrap: true,
highlight: true,
task: gui.createRenderStringWithoutScrollTask(patch),
task: NewRenderStringWithoutScrollTask(patch),
}
}

View File

@ -12,8 +12,7 @@ func (gui *Gui) onResize() error {
if gui.State.Ptmx == nil {
return nil
}
mainView := gui.getMainView()
width, height := mainView.Size()
width, height := gui.Views.Main.Size()
if err := pty.Setsize(gui.State.Ptmx, &pty.Winsize{Cols: uint16(width), Rows: uint16(height)}); err != nil {
return err
@ -31,7 +30,7 @@ func (gui *Gui) onResize() error {
// pseudo-terminal meaning we'll get the behaviour we want from the underlying
// command.
func (gui *Gui) newPtyTask(viewName string, cmd *exec.Cmd, prefix string) error {
width, _ := gui.getMainView().Size()
width, _ := gui.Views.Main.Size()
pager := gui.GitCommand.GetPager(width)
if pager == "" {

View File

@ -40,7 +40,7 @@ func (gui *Gui) handleShowAllBranchLogs() error {
cmd := gui.OSCommand.ExecutableFromString(
gui.Config.GetUserConfig().Git.AllBranchesLogCmd,
)
task := gui.createRunPtyTask(cmd)
task := NewRunPtyTask(cmd)
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{

View File

@ -20,13 +20,13 @@ func (gui *Gui) handleReflogCommitSelect() error {
commit := gui.getSelectedReflogCommit()
var task updateTask
if commit == nil {
task = gui.createRenderStringTask("No reflog history")
task = NewRenderStringTask("No reflog history")
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCmdStr(commit.Sha, gui.State.Modes.Filtering.GetPath()),
)
task = gui.createRunPtyTask(cmd)
task = NewRunPtyTask(cmd)
}
return gui.refreshMainViews(refreshMainOpts{

View File

@ -22,12 +22,12 @@ func (gui *Gui) handleRemoteBranchSelect() error {
var task updateTask
remoteBranch := gui.getSelectedRemoteBranch()
if remoteBranch == nil {
task = gui.createRenderStringTask("No branches for this remote")
task = NewRenderStringTask("No branches for this remote")
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(remoteBranch.FullName()),
)
task = gui.createRunCommandTask(cmd)
task = NewRunCommandTask(cmd)
}
return gui.refreshMainViews(refreshMainOpts{

View File

@ -24,9 +24,9 @@ func (gui *Gui) handleRemoteSelect() error {
var task updateTask
remote := gui.getSelectedRemote()
if remote == nil {
task = gui.createRenderStringTask("No remotes")
task = NewRenderStringTask("No remotes")
} else {
task = gui.createRenderStringTask(fmt.Sprintf("%s\nUrls:\n%s", utils.ColoredString(remote.Name, color.FgGreen), strings.Join(remote.Urls, "\n")))
task = NewRenderStringTask(fmt.Sprintf("%s\nUrls:\n%s", utils.ColoredString(remote.Name, color.FgGreen), strings.Join(remote.Urls, "\n")))
}
return gui.refreshMainViews(refreshMainOpts{
@ -57,12 +57,7 @@ func (gui *Gui) refreshRemotes() error {
}
}
branchesView := gui.getBranchesView()
if branchesView != nil {
return gui.postRefreshUpdate(gui.mustContextForContextKey(branchesView.Context))
}
return nil
return gui.postRefreshUpdate(gui.mustContextForContextKey(ContextKey(gui.Views.Branches.Context)))
}
func (gui *Gui) handleRemoteEnter() error {

View File

@ -26,7 +26,7 @@ func (gui *Gui) handleOpenSearch(viewName string) error {
}
func (gui *Gui) handleSearch() error {
gui.State.Searching.searchString = gui.getSearchView().Buffer()
gui.State.Searching.searchString = gui.Views.Search.Buffer()
if err := gui.returnFromContext(); err != nil {
return err
}

View File

@ -17,7 +17,7 @@ func (gui *Gui) nextSideWindow() error {
}
}
}
if err := gui.resetOrigin(gui.getMainView()); err != nil {
if err := gui.resetOrigin(gui.Views.Main); err != nil {
return err
}
@ -43,7 +43,7 @@ func (gui *Gui) previousSideWindow() error {
}
}
}
if err := gui.resetOrigin(gui.getMainView()); err != nil {
if err := gui.resetOrigin(gui.Views.Main); err != nil {
return err
}

View File

@ -26,11 +26,11 @@ func (gui *Gui) refreshStagingPanel(forceSecondaryFocused bool, selectedLineIdx
}
if secondaryFocused {
gui.getMainView().Title = gui.Tr.StagedChanges
gui.getSecondaryView().Title = gui.Tr.UnstagedChanges
gui.Views.Main.Title = gui.Tr.StagedChanges
gui.Views.Secondary.Title = gui.Tr.UnstagedChanges
} else {
gui.getMainView().Title = gui.Tr.UnstagedChanges
gui.getSecondaryView().Title = gui.Tr.StagedChanges
gui.Views.Main.Title = gui.Tr.UnstagedChanges
gui.Views.Secondary.Title = gui.Tr.StagedChanges
}
// note for custom diffs, we'll need to send a flag here saying not to use the custom diff
@ -63,7 +63,7 @@ func (gui *Gui) handleTogglePanelClick() error {
return gui.withLBLActiveCheck(func(state *lBlPanelState) error {
state.SecondaryFocused = !state.SecondaryFocused
return gui.refreshStagingPanel(false, gui.getSecondaryView().SelectedLineIdx(), state)
return gui.refreshStagingPanel(false, gui.Views.Secondary.SelectedLineIdx(), state)
})
}

View File

@ -20,12 +20,12 @@ func (gui *Gui) handleStashEntrySelect() error {
var task updateTask
stashEntry := gui.getSelectedStashEntry()
if stashEntry == nil {
task = gui.createRenderStringTask(gui.Tr.NoStashEntries)
task = NewRenderStringTask(gui.Tr.NoStashEntries)
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowStashEntryCmdStr(stashEntry.Index),
)
task = gui.createRunPtyTask(cmd)
task = NewRunPtyTask(cmd)
}
return gui.refreshMainViews(refreshMainOpts{

View File

@ -43,7 +43,7 @@ func (gui *Gui) refreshStatus() {
status += fmt.Sprintf("%s → %s ", repoName, name)
gui.g.Update(func(*gocui.Gui) error {
gui.setViewContent(gui.getStatusView(), status)
gui.setViewContent(gui.Views.Status, status)
return nil
})
}
@ -77,7 +77,7 @@ func (gui *Gui) handleStatusClick() error {
return err
}
cx, _ := gui.getStatusView().Cursor()
cx, _ := gui.Views.Status.Cursor()
upstreamStatus := fmt.Sprintf("↑%s↓%s", currentBranch.Pushables, currentBranch.Pullables)
repoName := utils.GetCurrentRepoName()
switch gui.GitCommand.WorkingTreeState() {
@ -121,7 +121,7 @@ func (gui *Gui) handleStatusSelect() error {
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{
title: "",
task: gui.createRenderStringTask(dashboardString),
task: NewRenderStringTask(dashboardString),
},
})
}

View File

@ -21,13 +21,13 @@ func (gui *Gui) handleSubCommitSelect() error {
commit := gui.getSelectedSubCommit()
var task updateTask
if commit == nil {
task = gui.createRenderStringTask("No commits")
task = NewRenderStringTask("No commits")
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCmdStr(commit.Sha, gui.State.Modes.Filtering.GetPath()),
)
task = gui.createRunPtyTask(cmd)
task = NewRunPtyTask(cmd)
}
return gui.refreshMainViews(refreshMainOpts{
@ -94,13 +94,13 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error {
gui.State.SubCommits = commits
gui.State.Panels.SubCommits.refName = refName
gui.State.Panels.SubCommits.SelectedLineIdx = 0
gui.State.Contexts.SubCommits.SetParentContext(gui.currentSideContext())
gui.State.Contexts.SubCommits.SetParentContext(gui.currentSideListContext())
return gui.pushContext(gui.State.Contexts.SubCommits)
}
func (gui *Gui) handleSwitchToSubCommits() error {
currentContext := gui.currentSideContext()
currentContext := gui.currentSideListContext()
if currentContext == nil {
return nil
}

View File

@ -24,7 +24,7 @@ func (gui *Gui) handleSubmoduleSelect() error {
var task updateTask
submodule := gui.getSelectedSubmodule()
if submodule == nil {
task = gui.createRenderStringTask("No submodules")
task = NewRenderStringTask("No submodules")
} else {
prefix := fmt.Sprintf(
"Name: %s\nPath: %s\nUrl: %s\n\n",
@ -35,11 +35,11 @@ func (gui *Gui) handleSubmoduleSelect() error {
file := gui.fileForSubmodule(submodule)
if file == nil {
task = gui.createRenderStringTask(prefix)
task = NewRenderStringTask(prefix)
} else {
cmdStr := gui.GitCommand.WorktreeFileDiffCmdStr(file, false, !file.HasUnstagedChanges && file.HasStagedChanges)
cmd := gui.OSCommand.ExecutableFromString(cmdStr)
task = gui.createRunCommandTaskWithPrefix(cmd, prefix)
task = NewRunCommandTaskWithPrefix(cmd, prefix)
}
}

View File

@ -24,13 +24,8 @@ func (gui *Gui) getSelectedSuggestion() *types.Suggestion {
}
func (gui *Gui) setSuggestions(suggestions []*types.Suggestion) {
view := gui.getSuggestionsView()
if view == nil {
return
}
gui.State.Suggestions = suggestions
gui.State.Panels.Suggestions.SelectedLineIdx = 0
_ = gui.resetOrigin(view)
_ = gui.resetOrigin(gui.Views.Suggestions)
_ = gui.State.Contexts.Suggestions.HandleRender()
}

View File

@ -5,8 +5,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils"
)
// list panel functions
func (gui *Gui) getSelectedTag() *models.Tag {
selectedLine := gui.State.Panels.Tags.SelectedLineIdx
if selectedLine == -1 || len(gui.State.Tags) == 0 {
@ -16,100 +14,6 @@ func (gui *Gui) getSelectedTag() *models.Tag {
return gui.State.Tags[selectedLine]
}
func (gui *Gui) handleTagSelect() error {
var task updateTask
tag := gui.getSelectedTag()
if tag == nil {
task = gui.createRenderStringTask("No tags")
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(tag.Name),
)
task = gui.createRunCommandTask(cmd)
}
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{
title: "Tag",
task: task,
},
})
}
func (gui *Gui) refreshTags() error {
tags, err := gui.GitCommand.GetTags()
if err != nil {
return gui.surfaceError(err)
}
gui.State.Tags = tags
return gui.postRefreshUpdate(gui.State.Contexts.Tags)
}
func (gui *Gui) handleCheckoutTag() error {
tag := gui.getSelectedTag()
if tag == nil {
return nil
}
if err := gui.handleCheckoutRef(tag.Name, handleCheckoutRefOptions{}); err != nil {
return err
}
return gui.pushContext(gui.State.Contexts.Branches)
}
func (gui *Gui) handleDeleteTag() error {
tag := gui.getSelectedTag()
if tag == nil {
return nil
}
prompt := utils.ResolvePlaceholderString(
gui.Tr.DeleteTagPrompt,
map[string]string{
"tagName": tag.Name,
},
)
return gui.ask(askOpts{
title: gui.Tr.DeleteTagTitle,
prompt: prompt,
handleConfirm: func() error {
if err := gui.GitCommand.DeleteTag(tag.Name); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{COMMITS, TAGS}})
},
})
}
func (gui *Gui) handlePushTag() error {
tag := gui.getSelectedTag()
if tag == nil {
return nil
}
title := utils.ResolvePlaceholderString(
gui.Tr.PushTagTitle,
map[string]string{
"tagName": tag.Name,
},
)
return gui.prompt(promptOpts{
title: title,
initialContent: "origin",
handleConfirm: func(response string) error {
return gui.WithWaitingStatus(gui.Tr.PushingTagStatus, func() error {
err := gui.GitCommand.PushTag(response, tag.Name, gui.promptUserForCredential)
gui.handleCredentialsPopup(err)
return nil
})
},
})
}
func (gui *Gui) handleCreateTag() error {
return gui.prompt(promptOpts{
title: gui.Tr.CreateTagTitle,
@ -136,11 +40,98 @@ func (gui *Gui) handleCreateTag() error {
})
}
func (gui *Gui) handleCreateResetToTagMenu() error {
// tag-specific handlers
// view model would need to raise an event called 'tag selected', perhaps containing a tag. The listener would _be_ the main view, or the main context, and it would be able to render to itself.
func (gui *Gui) handleTagSelect() error {
var task updateTask
tag := gui.getSelectedTag()
if tag == nil {
task = NewRenderStringTask("No tags")
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(tag.Name),
)
task = NewRunCommandTask(cmd)
}
return gui.refreshMainViews(refreshMainOpts{
main: &viewUpdateOpts{
title: "Tag",
task: task,
},
})
}
// this is a controller: it can't access tags directly. Or can it? It should be able to get but not set. But that's exactly what I'm doing here, setting it. but through a mutator which encapsulates the event.
func (gui *Gui) refreshTags() error {
tags, err := gui.GitCommand.GetTags()
if err != nil {
return gui.surfaceError(err)
}
gui.State.Tags = tags
return gui.postRefreshUpdate(gui.State.Contexts.Tags)
}
func (gui *Gui) withSelectedTag(f func(tag *models.Tag) error) func() error {
tag := gui.getSelectedTag()
if tag == nil {
return nil
}
return func() error { return f(tag) }
}
func (gui *Gui) handleCheckoutTag(tag *models.Tag) error {
if err := gui.handleCheckoutRef(tag.Name, handleCheckoutRefOptions{}); err != nil {
return err
}
return gui.pushContext(gui.State.Contexts.Branches)
}
func (gui *Gui) handleDeleteTag(tag *models.Tag) error {
prompt := utils.ResolvePlaceholderString(
gui.Tr.DeleteTagPrompt,
map[string]string{
"tagName": tag.Name,
},
)
return gui.ask(askOpts{
title: gui.Tr.DeleteTagTitle,
prompt: prompt,
handleConfirm: func() error {
if err := gui.GitCommand.DeleteTag(tag.Name); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{COMMITS, TAGS}})
},
})
}
func (gui *Gui) handlePushTag(tag *models.Tag) error {
title := utils.ResolvePlaceholderString(
gui.Tr.PushTagTitle,
map[string]string{
"tagName": tag.Name,
},
)
return gui.prompt(promptOpts{
title: title,
initialContent: "origin",
handleConfirm: func(response string) error {
return gui.WithWaitingStatus(gui.Tr.PushingTagStatus, func() error {
err := gui.GitCommand.PushTag(response, tag.Name, gui.promptUserForCredential)
gui.handleCredentialsPopup(err)
return nil
})
},
})
}
func (gui *Gui) handleCreateResetToTagMenu(tag *models.Tag) error {
return gui.createResetMenu(tag.Name)
}

View File

@ -241,88 +241,6 @@ func (gui *Gui) renderOptionsMap(optionsMap map[string]string) {
gui.renderString("options", gui.optionsMapToString(optionsMap))
}
func (gui *Gui) getFilesView() *gocui.View {
v, _ := gui.g.View("files")
return v
}
func (gui *Gui) getCommitFilesView() *gocui.View {
v, _ := gui.g.View("commitFiles")
return v
}
func (gui *Gui) getCommitsView() *gocui.View {
v, _ := gui.g.View("commits")
return v
}
func (gui *Gui) getCredentialsView() *gocui.View {
v, _ := gui.g.View("commits")
return v
}
func (gui *Gui) getCommitMessageView() *gocui.View {
v, _ := gui.g.View("commitMessage")
return v
}
func (gui *Gui) getBranchesView() *gocui.View {
v, _ := gui.g.View("branches")
return v
}
func (gui *Gui) getMainView() *gocui.View {
v, _ := gui.g.View("main")
return v
}
func (gui *Gui) getSuggestionsView() *gocui.View {
v, _ := gui.g.View("suggestions")
return v
}
func (gui *Gui) getSecondaryView() *gocui.View {
v, _ := gui.g.View("secondary")
return v
}
// currently unused
// func (gui *Gui) getStashView() *gocui.View {
// v, _ := gui.g.View("stash")
// return v
// }
// currently unused
// func (gui *Gui) getCommitFilesView() *gocui.View {
// v, _ := gui.g.View("commitFiles")
// return v
// }
func (gui *Gui) getMenuView() *gocui.View {
v, _ := gui.g.View("menu")
return v
}
func (gui *Gui) getSearchView() *gocui.View {
v, _ := gui.g.View("search")
return v
}
func (gui *Gui) getStatusView() *gocui.View {
v, _ := gui.g.View("status")
return v
}
func (gui *Gui) getConfirmationView() *gocui.View {
v, _ := gui.g.View("confirmation")
return v
}
func (gui *Gui) getInformationView() *gocui.View {
v, _ := gui.g.View("information")
return v
}
func (gui *Gui) trimmedContent(v *gocui.View) string {
return strings.TrimSpace(v.Buffer())
}