1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-09 13:47:11 +02:00

lots more refactoring

This commit is contained in:
Jesse Duffield 2023-03-21 20:57:52 +11:00
parent 8edad826ca
commit 509e3efa70
45 changed files with 779 additions and 729 deletions

View File

@ -1,38 +0,0 @@
package gui
import (
"strconv"
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/utils"
)
func (gui *Gui) handleCommitMessageFocused() error {
message := utils.ResolvePlaceholderString(
gui.c.Tr.CommitMessageConfirm,
map[string]string{
"keyBindClose": keybindings.Label(gui.c.UserConfig.Keybinding.Universal.Return),
"keyBindConfirm": keybindings.Label(gui.c.UserConfig.Keybinding.Universal.Confirm),
"keyBindNewLine": keybindings.Label(gui.c.UserConfig.Keybinding.Universal.AppendNewline),
},
)
gui.RenderCommitLength()
gui.c.SetViewContent(gui.Views.Options, message)
return nil
}
func (gui *Gui) RenderCommitLength() {
if !gui.c.UserConfig.Gui.CommitLength.Show {
return
}
gui.Views.CommitMessage.Subtitle = getBufferLength(gui.Views.CommitMessage)
}
func getBufferLength(view *gocui.View) string {
return " " + strconv.Itoa(strings.Count(view.TextArea.GetContent(), "")-1) + " "
}

View File

@ -1,316 +0,0 @@
package gui
import (
"context"
"fmt"
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/mattn/go-runewidth"
)
// This file is for the rendering of confirmation panels along with setting and handling associated
// keybindings.
func (gui *Gui) wrappedConfirmationFunction(cancel context.CancelFunc, function func() error) func() error {
return func() error {
cancel()
if err := gui.c.PopContext(); err != nil {
return err
}
if function != nil {
if err := function(); err != nil {
return gui.c.Error(err)
}
}
return nil
}
}
func (gui *Gui) wrappedPromptConfirmationFunction(cancel context.CancelFunc, function func(string) error, getResponse func() string) func() error {
return func() error {
cancel()
if err := gui.c.PopContext(); err != nil {
return err
}
if function != nil {
if err := function(getResponse()); err != nil {
return gui.c.Error(err)
}
}
return nil
}
}
func (gui *Gui) deactivateConfirmationPrompt() {
gui.Mutexes.PopupMutex.Lock()
gui.State.CurrentPopupOpts = nil
gui.Mutexes.PopupMutex.Unlock()
gui.Views.Confirmation.Visible = false
gui.Views.Suggestions.Visible = false
gui.clearConfirmationViewKeyBindings()
}
func (gui *Gui) getMessageHeight(wrap bool, message string, width int) int {
lines := strings.Split(message, "\n")
lineCount := 0
// if we need to wrap, calculate height to fit content within view's width
if wrap {
for _, line := range lines {
lineCount += runewidth.StringWidth(line)/width + 1
}
} else {
lineCount = len(lines)
}
return lineCount
}
func (gui *Gui) getConfirmationPanelDimensions(wrap bool, prompt string) (int, int, int, int) {
panelWidth := gui.getConfirmationPanelWidth()
panelHeight := gui.getMessageHeight(wrap, prompt, panelWidth)
return gui.getConfirmationPanelDimensionsAux(panelWidth, panelHeight)
}
func (gui *Gui) getConfirmationPanelDimensionsForContentHeight(panelWidth, contentHeight int) (int, int, int, int) {
return gui.getConfirmationPanelDimensionsAux(panelWidth, contentHeight)
}
func (gui *Gui) getConfirmationPanelDimensionsAux(panelWidth int, panelHeight int) (int, int, int, int) {
width, height := gui.g.Size()
if panelHeight > height*3/4 {
panelHeight = height * 3 / 4
}
return width/2 - panelWidth/2,
height/2 - panelHeight/2 - panelHeight%2 - 1,
width/2 + panelWidth/2,
height/2 + panelHeight/2
}
func (gui *Gui) getConfirmationPanelWidth() int {
width, _ := gui.g.Size()
// we want a minimum width up to a point, then we do it based on ratio.
panelWidth := 4 * width / 7
minWidth := 80
if panelWidth < minWidth {
if width-2 < minWidth {
panelWidth = width - 2
} else {
panelWidth = minWidth
}
}
return panelWidth
}
func (gui *Gui) prepareConfirmationPanel(
ctx context.Context,
opts types.ConfirmOpts,
) error {
gui.Views.Confirmation.HasLoader = opts.HasLoader
if opts.HasLoader {
gui.g.StartTicking(ctx)
}
gui.Views.Confirmation.Title = opts.Title
// for now we do not support wrapping in our editor
gui.Views.Confirmation.Wrap = !opts.Editable
gui.Views.Confirmation.FgColor = theme.GocuiDefaultTextColor
gui.Views.Confirmation.Mask = runeForMask(opts.Mask)
_ = gui.Views.Confirmation.SetOrigin(0, 0)
gui.findSuggestions = opts.FindSuggestionsFunc
if opts.FindSuggestionsFunc != nil {
suggestionsView := gui.Views.Suggestions
suggestionsView.Wrap = false
suggestionsView.FgColor = theme.GocuiDefaultTextColor
gui.setSuggestions(opts.FindSuggestionsFunc(""))
suggestionsView.Visible = true
suggestionsView.Title = fmt.Sprintf(gui.c.Tr.SuggestionsTitle, gui.c.UserConfig.Keybinding.Universal.TogglePanel)
}
gui.resizeConfirmationPanel()
return nil
}
func runeForMask(mask bool) rune {
if mask {
return '*'
}
return 0
}
func (gui *Gui) createPopupPanel(ctx context.Context, opts types.CreatePopupPanelOpts) error {
gui.Mutexes.PopupMutex.Lock()
defer gui.Mutexes.PopupMutex.Unlock()
ctx, cancel := context.WithCancel(ctx)
// we don't allow interruptions of non-loader popups in case we get stuck somehow
// e.g. a credentials popup never gets its required user input so a process hangs
// forever.
// The proper solution is to have a queue of popup options
if gui.State.CurrentPopupOpts != nil && !gui.State.CurrentPopupOpts.HasLoader {
gui.Log.Error("ignoring create popup panel because a popup panel is already open")
cancel()
return nil
}
// remove any previous keybindings
gui.clearConfirmationViewKeyBindings()
err := gui.prepareConfirmationPanel(
ctx,
types.ConfirmOpts{
Title: opts.Title,
Prompt: opts.Prompt,
HasLoader: opts.HasLoader,
FindSuggestionsFunc: opts.FindSuggestionsFunc,
Editable: opts.Editable,
Mask: opts.Mask,
})
if err != nil {
cancel()
return err
}
confirmationView := gui.Views.Confirmation
confirmationView.Editable = opts.Editable
confirmationView.Editor = gocui.EditorFunc(gui.defaultEditor)
if opts.Editable {
textArea := confirmationView.TextArea
textArea.Clear()
textArea.TypeString(opts.Prompt)
gui.resizeConfirmationPanel()
confirmationView.RenderTextArea()
} else {
gui.c.ResetViewOrigin(confirmationView)
gui.c.SetViewContent(confirmationView, style.AttrBold.Sprint(opts.Prompt))
}
if err := gui.setKeyBindings(cancel, opts); err != nil {
cancel()
return err
}
gui.State.CurrentPopupOpts = &opts
return gui.c.PushContext(gui.State.Contexts.Confirmation)
}
func (gui *Gui) setKeyBindings(cancel context.CancelFunc, opts types.CreatePopupPanelOpts) error {
actions := utils.ResolvePlaceholderString(
gui.c.Tr.CloseConfirm,
map[string]string{
"keyBindClose": "esc",
"keyBindConfirm": "enter",
},
)
gui.c.SetViewContent(gui.Views.Options, actions)
var onConfirm func() error
if opts.HandleConfirmPrompt != nil {
onConfirm = gui.wrappedPromptConfirmationFunction(cancel, opts.HandleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() })
} else {
onConfirm = gui.wrappedConfirmationFunction(cancel, opts.HandleConfirm)
}
keybindingConfig := gui.c.UserConfig.Keybinding
onSuggestionConfirm := gui.wrappedPromptConfirmationFunction(
cancel,
opts.HandleConfirmPrompt,
gui.getSelectedSuggestionValue,
)
bindings := []*types.Binding{
{
ViewName: "confirmation",
Key: keybindings.GetKey(keybindingConfig.Universal.Confirm),
Handler: onConfirm,
},
{
ViewName: "confirmation",
Key: keybindings.GetKey(keybindingConfig.Universal.Return),
Handler: gui.wrappedConfirmationFunction(cancel, opts.HandleClose),
},
{
ViewName: "confirmation",
Key: keybindings.GetKey(keybindingConfig.Universal.TogglePanel),
Handler: func() error {
if len(gui.State.Suggestions) > 0 {
return gui.c.ReplaceContext(gui.State.Contexts.Suggestions)
}
return nil
},
},
{
ViewName: "suggestions",
Key: keybindings.GetKey(keybindingConfig.Universal.Confirm),
Handler: onSuggestionConfirm,
},
{
ViewName: "suggestions",
Key: keybindings.GetKey(keybindingConfig.Universal.Return),
Handler: gui.wrappedConfirmationFunction(cancel, opts.HandleClose),
},
{
ViewName: "suggestions",
Key: keybindings.GetKey(keybindingConfig.Universal.TogglePanel),
Handler: func() error { return gui.c.ReplaceContext(gui.State.Contexts.Confirmation) },
},
}
for _, binding := range bindings {
if err := gui.SetKeybinding(binding); err != nil {
return err
}
}
return nil
}
func (gui *Gui) clearConfirmationViewKeyBindings() {
keybindingConfig := gui.c.UserConfig.Keybinding
_ = gui.g.DeleteKeybinding("confirmation", keybindings.GetKey(keybindingConfig.Universal.Confirm), gocui.ModNone)
_ = gui.g.DeleteKeybinding("confirmation", keybindings.GetKey(keybindingConfig.Universal.Return), gocui.ModNone)
_ = gui.g.DeleteKeybinding("suggestions", keybindings.GetKey(keybindingConfig.Universal.Confirm), gocui.ModNone)
_ = gui.g.DeleteKeybinding("suggestions", keybindings.GetKey(keybindingConfig.Universal.Return), gocui.ModNone)
}
func (gui *Gui) refreshSuggestions() {
gui.suggestionsAsyncHandler.Do(func() func() {
findSuggestionsFn := gui.findSuggestions
if findSuggestionsFn != nil {
suggestions := gui.findSuggestions(gui.c.GetPromptInput())
return func() { gui.setSuggestions(suggestions) }
} else {
return func() {}
}
})
}
func (gui *Gui) handleAskFocused() error {
keybindingConfig := gui.c.UserConfig.Keybinding
message := utils.ResolvePlaceholderString(
gui.c.Tr.CloseConfirm,
map[string]string{
"keyBindClose": keybindings.Label(keybindingConfig.Universal.Return),
"keyBindConfirm": keybindings.Label(keybindingConfig.Universal.Confirm),
},
)
gui.c.SetViewContent(gui.Views.Options, message)
return nil
}

View File

@ -0,0 +1,47 @@
package context
import (
"strconv"
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type CommitMessageContext struct {
*SimpleContext
c *types.HelperCommon
}
var _ types.Context = (*CommitMessageContext)(nil)
func NewCommitMessageContext(
c *types.HelperCommon,
) *CommitMessageContext {
return &CommitMessageContext{
c: c,
SimpleContext: NewSimpleContext(
NewBaseContext(NewBaseContextOpts{
Kind: types.PERSISTENT_POPUP,
View: c.Views().CommitMessage,
WindowName: "commitMessage",
Key: COMMIT_MESSAGE_CONTEXT_KEY,
Focusable: true,
HasUncontrolledBounds: true,
}),
ContextCallbackOpts{},
),
}
}
func (self *CommitMessageContext) RenderCommitLength() {
if !self.c.UserConfig.Gui.CommitLength.Show {
return
}
self.c.Views().CommitMessage.Subtitle = getBufferLength(self.c.Views().CommitMessage)
}
func getBufferLength(view *gocui.View) string {
return " " + strconv.Itoa(strings.Count(view.TextArea.GetContent(), "")-1) + " "
}

View File

@ -0,0 +1,35 @@
package context
import (
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type ConfirmationContext struct {
*SimpleContext
c *types.HelperCommon
State ConfirmationContextState
}
type ConfirmationContextState struct {
OnConfirm func() error
OnClose func() error
}
var _ types.Context = (*ConfirmationContext)(nil)
func NewConfirmationContext(
c *types.HelperCommon,
) *ConfirmationContext {
return &ConfirmationContext{
c: c,
SimpleContext: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
View: c.Views().Confirmation,
WindowName: "confirmation",
Key: CONFIRMATION_CONTEXT_KEY,
Kind: types.TEMPORARY_POPUP,
Focusable: true,
HasUncontrolledBounds: true,
}), ContextCallbackOpts{}),
}
}

View File

@ -96,8 +96,8 @@ type ContextTree struct {
CustomPatchBuilder *PatchExplorerContext
CustomPatchBuilderSecondary types.Context
MergeConflicts *MergeConflictsContext
Confirmation types.Context
CommitMessage types.Context
Confirmation *ConfirmationContext
CommitMessage *CommitMessageContext
CommandLog types.Context
// display contexts

View File

@ -2,7 +2,6 @@ package context
import (
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
@ -16,11 +15,7 @@ type MenuContext struct {
var _ types.IListContext = (*MenuContext)(nil)
func NewMenuContext(
view *gocui.View,
c *types.HelperCommon,
getOptionsMap func() map[string]string,
renderToDescriptionView func(string),
) *MenuContext {
viewModel := NewMenuViewModel()
@ -28,11 +23,10 @@ func NewMenuContext(
MenuViewModel: viewModel,
ListContextTrait: &ListContextTrait{
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
View: view,
View: c.Views().Menu,
WindowName: "menu",
Key: "menu",
Kind: types.TEMPORARY_POPUP,
OnGetOptionsMap: getOptionsMap,
Focusable: true,
HasUncontrolledBounds: true,
}), ContextCallbackOpts{}),

View File

@ -30,7 +30,6 @@ func NewMergeConflictsContext(
opts ContextCallbackOpts,
c *types.HelperCommon,
getOptionsMap func() map[string]string,
) *MergeConflictsContext {
viewModel := &ConflictsViewModel{
state: mergeconflicts.NewState(),
@ -46,7 +45,6 @@ func NewMergeConflictsContext(
View: view,
WindowName: "main",
Key: MERGE_CONFLICTS_CONTEXT_KEY,
OnGetOptionsMap: getOptionsMap,
Focusable: true,
HighlightOnFocus: true,
}),

View File

@ -24,8 +24,6 @@ func NewPatchExplorerContext(
windowName string,
key types.ContextKey,
onFocus func(types.OnFocusOpts) error,
onFocusLost func(opts types.OnFocusLostOpts) error,
getIncludedLineIndices func() []int,
c *types.HelperCommon,
@ -43,10 +41,7 @@ func NewPatchExplorerContext(
Kind: types.MAIN_CONTEXT,
Focusable: true,
HighlightOnFocus: true,
}), ContextCallbackOpts{
OnFocus: onFocus,
OnFocusLost: onFocusLost,
}),
}), ContextCallbackOpts{}),
}
}

View File

@ -1,31 +1,53 @@
package context
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/tasks"
)
type SuggestionsContext struct {
*BasicViewModel[*types.Suggestion]
*ListContextTrait
State *SuggestionsContextState
}
type SuggestionsContextState struct {
Suggestions []*types.Suggestion
OnConfirm func() error
OnClose func() error
AsyncHandler *tasks.AsyncHandler
// FindSuggestions will take a string that the user has typed into a prompt
// and return a slice of suggestions which match that string.
FindSuggestions func(string) []*types.Suggestion
}
var _ types.IListContext = (*SuggestionsContext)(nil)
func NewSuggestionsContext(
getModel func() []*types.Suggestion,
view *gocui.View,
getDisplayStrings func(startIdx int, length int) [][]string,
c *types.HelperCommon,
) *SuggestionsContext {
state := &SuggestionsContextState{
AsyncHandler: tasks.NewAsyncHandler(),
}
getModel := func() []*types.Suggestion {
return state.Suggestions
}
getDisplayStrings := func(startIdx int, length int) [][]string {
return presentation.GetSuggestionListDisplayStrings(state.Suggestions)
}
viewModel := NewBasicViewModel(getModel)
return &SuggestionsContext{
State: state,
BasicViewModel: viewModel,
ListContextTrait: &ListContextTrait{
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
View: view,
View: c.Views().Suggestions,
WindowName: "suggestions",
Key: SUGGESTIONS_CONTEXT_KEY,
Kind: types.PERSISTENT_POPUP,
@ -47,3 +69,22 @@ func (self *SuggestionsContext) GetSelectedItemId() string {
return item.Value
}
func (self *SuggestionsContext) SetSuggestions(suggestions []*types.Suggestion) {
self.State.Suggestions = suggestions
self.SetSelectedLineIdx(0)
self.c.ResetViewOrigin(self.GetView())
_ = self.HandleRender()
}
func (self *SuggestionsContext) RefreshSuggestions() {
self.State.AsyncHandler.Do(func() func() {
findSuggestionsFn := self.State.FindSuggestions
if findSuggestionsFn != nil {
suggestions := findSuggestionsFn(self.c.GetPromptInput())
return func() { self.SetSuggestions(suggestions) }
} else {
return func() {}
}
})
}

View File

@ -76,23 +76,6 @@ func (gui *Gui) contextTree() *context.ContextTree {
gui.Views.Staging,
"main",
context.STAGING_MAIN_CONTEXT_KEY,
func(opts types.OnFocusOpts) error {
gui.Views.Staging.Wrap = false
gui.Views.StagingSecondary.Wrap = false
return gui.helpers.Staging.RefreshStagingPanel(opts)
},
func(opts types.OnFocusLostOpts) error {
gui.State.Contexts.Staging.SetState(nil)
if opts.NewContextKey != context.STAGING_SECONDARY_CONTEXT_KEY {
gui.Views.Staging.Wrap = true
gui.Views.StagingSecondary.Wrap = true
_ = gui.State.Contexts.Staging.Render(false)
_ = gui.State.Contexts.StagingSecondary.Render(false)
}
return nil
},
func() []int { return nil },
gui.c,
),
@ -100,23 +83,6 @@ func (gui *Gui) contextTree() *context.ContextTree {
gui.Views.StagingSecondary,
"secondary",
context.STAGING_SECONDARY_CONTEXT_KEY,
func(opts types.OnFocusOpts) error {
gui.Views.Staging.Wrap = false
gui.Views.StagingSecondary.Wrap = false
return gui.helpers.Staging.RefreshStagingPanel(opts)
},
func(opts types.OnFocusLostOpts) error {
gui.State.Contexts.StagingSecondary.SetState(nil)
if opts.NewContextKey != context.STAGING_MAIN_CONTEXT_KEY {
gui.Views.Staging.Wrap = true
gui.Views.StagingSecondary.Wrap = true
_ = gui.State.Contexts.Staging.Render(false)
_ = gui.State.Contexts.StagingSecondary.Render(false)
}
return nil
},
func() []int { return nil },
gui.c,
),
@ -124,21 +90,6 @@ func (gui *Gui) contextTree() *context.ContextTree {
gui.Views.PatchBuilding,
"main",
context.PATCH_BUILDING_MAIN_CONTEXT_KEY,
func(opts types.OnFocusOpts) error {
// no need to change wrap on the secondary view because it can't be interacted with
gui.Views.PatchBuilding.Wrap = false
return gui.helpers.PatchBuilding.RefreshPatchBuildingPanel(opts)
},
func(opts types.OnFocusLostOpts) error {
gui.Views.PatchBuilding.Wrap = true
if gui.git.Patch.PatchBuilder.IsEmpty() {
gui.git.Patch.PatchBuilder.Reset()
}
return nil
},
func() []int {
filename := gui.State.Contexts.CommitFiles.GetSelectedPath()
includedLineIndices, err := gui.git.Patch.PatchBuilder.GetFileIncLineIndices(filename)
@ -165,37 +116,9 @@ func (gui *Gui) contextTree() *context.ContextTree {
gui.Views.MergeConflicts,
context.ContextCallbackOpts{},
gui.c,
func() map[string]string {
// wrapping in a function because contexts are initialized before helpers
return gui.helpers.MergeConflicts.GetMergingOptions()
},
),
Confirmation: context.NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.TEMPORARY_POPUP,
View: gui.Views.Confirmation,
WindowName: "confirmation",
Key: context.CONFIRMATION_CONTEXT_KEY,
Focusable: true,
HasUncontrolledBounds: true,
}),
context.ContextCallbackOpts{
OnFocus: OnFocusWrapper(gui.handleAskFocused),
},
),
CommitMessage: context.NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.PERSISTENT_POPUP,
View: gui.Views.CommitMessage,
WindowName: "commitMessage",
Key: context.COMMIT_MESSAGE_CONTEXT_KEY,
Focusable: true,
HasUncontrolledBounds: true,
}),
context.ContextCallbackOpts{
OnFocus: OnFocusWrapper(gui.handleCommitMessageFocused),
},
),
Confirmation: context.NewConfirmationContext(gui.c),
CommitMessage: context.NewCommitMessageContext(gui.c),
Search: context.NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.PERSISTENT_POPUP,
@ -214,12 +137,7 @@ func (gui *Gui) contextTree() *context.ContextTree {
Key: context.COMMAND_LOG_CONTEXT_KEY,
Focusable: true,
}),
context.ContextCallbackOpts{
OnFocusLost: func(opts types.OnFocusLostOpts) error {
gui.Views.Extras.Autoscroll = true
return nil
},
},
context.ContextCallbackOpts{},
),
Options: context.NewDisplayContext(context.OPTIONS_CONTEXT_KEY, gui.Views.Options, "options"),
AppStatus: context.NewDisplayContext(context.APP_STATUS_CONTEXT_KEY, gui.Views.AppStatus, "appStatus"),

View File

@ -24,7 +24,7 @@ func (gui *Gui) resetControllers() {
)
rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, refsHelper)
suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions)
suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon, model, gui.State.Contexts)
setCommitMessage := gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage })
getSavedCommitMessage := func() string {
return gui.State.savedCommitMessage
@ -66,6 +66,7 @@ func (gui *Gui) resetControllers() {
Window: helpers.NewWindowHelper(helperCommon, viewHelper, gui.State.Contexts),
View: viewHelper,
Refresh: refreshHelper,
Confirmation: helpers.NewConfirmationHelper(helperCommon, gui.State.Contexts),
}
gui.CustomCommandsClient = custom_commands.NewClient(
@ -151,6 +152,9 @@ func (gui *Gui) resetControllers() {
reflogCommitsController := controllers.NewReflogCommitsController(common, gui.State.Contexts.ReflogCommits)
subCommitsController := controllers.NewSubCommitsController(common, gui.State.Contexts.SubCommits)
statusController := controllers.NewStatusController(common)
commandLogController := controllers.NewCommandLogController(common)
confirmationController := controllers.NewConfirmationController(common)
suggestionsController := controllers.NewSuggestionsController(common)
setSubCommits := func(commits []*models.Commit) {
gui.Mutexes.SubCommitsMutex.Lock()
@ -279,6 +283,18 @@ func (gui *Gui) resetControllers() {
statusController,
)
controllers.AttachControllers(gui.State.Contexts.CommandLog,
commandLogController,
)
controllers.AttachControllers(gui.State.Contexts.Confirmation,
confirmationController,
)
controllers.AttachControllers(gui.State.Contexts.Suggestions,
suggestionsController,
)
controllers.AttachControllers(gui.State.Contexts.Global,
syncController,
undoController,
@ -303,7 +319,7 @@ func (gui *Gui) getSetTextareaTextFn(getView func() *gocui.View) func(string) {
view := getView()
view.ClearTextArea()
view.TextArea.TypeString(text)
_ = gui.resizePopupPanel(view, view.TextArea.GetContent())
_ = gui.helpers.Confirmation.ResizePopupPanel(view, view.TextArea.GetContent())
view.RenderTextArea()
}
}

View File

@ -0,0 +1,42 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type CommandLogController struct {
baseController
*controllerCommon
}
var _ types.IController = &CommandLogController{}
func NewCommandLogController(
common *controllerCommon,
) *CommandLogController {
return &CommandLogController{
baseController: baseController{},
controllerCommon: common,
}
}
func (self *CommandLogController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
bindings := []*types.Binding{}
return bindings
}
func (self *CommandLogController) GetOnFocusLost() func(types.OnFocusLostOpts) error {
return func(types.OnFocusLostOpts) error {
self.c.Views().Extras.Autoscroll = true
return nil
}
}
func (self *CommandLogController) Context() types.Context {
return self.context()
}
func (self *CommandLogController) context() types.Context {
return self.contexts.CommandLog
}

View File

@ -1,6 +1,7 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -31,28 +32,39 @@ func NewCommitMessageController(
}
}
// TODO: merge that commit panel PR because we're not currently showing how to add a newline as it's
// handled by the editor func rather than by the controller here.
func (self *CommitMessageController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
bindings := []*types.Binding{
{
Key: opts.GetKey(opts.Config.Universal.SubmitEditorText),
Handler: self.confirm,
Key: opts.GetKey(opts.Config.Universal.SubmitEditorText),
Handler: self.confirm,
Description: self.c.Tr.LcConfirm,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: self.close,
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: self.close,
Description: self.c.Tr.LcClose,
},
}
return bindings
}
func (self *CommitMessageController) GetOnFocusLost() func(types.OnFocusLostOpts) error {
return func(types.OnFocusLostOpts) error {
self.context().RenderCommitLength()
return nil
}
}
func (self *CommitMessageController) Context() types.Context {
return self.context()
}
// this method is pointless in this context but I'm keeping it consistent
// with other contexts so that when generics arrive it's easier to refactor
func (self *CommitMessageController) context() types.Context {
func (self *CommitMessageController) context() *context.CommitMessageContext {
return self.contexts.CommitMessage
}

View File

@ -1,6 +1,7 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -21,14 +22,36 @@ func NewConfirmationController(
}
func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
bindings := []*types.Binding{}
bindings := []*types.Binding{
{
Key: opts.GetKey(opts.Config.Universal.Confirm),
Handler: func() error { return self.context().State.OnConfirm() },
Description: self.c.Tr.LcConfirm,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: func() error { return self.context().State.OnClose() },
Description: self.c.Tr.LcCloseCancel,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
Handler: func() error {
if len(self.contexts.Suggestions.State.Suggestions) > 0 {
return self.c.ReplaceContext(self.contexts.Suggestions)
}
return nil
},
},
}
return bindings
}
func (self *ConfirmationController) GetOnFocusLost() func(types.OnFocusLostOpts) error {
return func(types.OnFocusLostOpts) error {
deactivateConfirmationPrompt(self.controllerCommon)
self.helpers.Confirmation.DeactivateConfirmationPrompt()
return nil
}
}
@ -37,17 +60,6 @@ func (self *ConfirmationController) Context() types.Context {
return self.context()
}
func (self *ConfirmationController) context() types.Context {
func (self *ConfirmationController) context() *context.ConfirmationContext {
return self.contexts.Confirmation
}
func deactivateConfirmationPrompt(c *controllerCommon) {
c.mutexes.PopupMutex.Lock()
c.c.State().GetRepoState().SetCurrentPopupOpts(nil)
c.mutexes.PopupMutex.Unlock()
c.c.Views().Confirmation.Visible = false
c.c.Views().Suggestions.Visible = false
gui.clearConfirmationViewKeyBindings()
}

View File

@ -0,0 +1,321 @@
package helpers
import (
goContext "context"
"fmt"
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/theme"
"github.com/mattn/go-runewidth"
)
type ConfirmationHelper struct {
c *types.HelperCommon
contexts *context.ContextTree
}
func NewConfirmationHelper(
c *types.HelperCommon,
contexts *context.ContextTree,
) *ConfirmationHelper {
return &ConfirmationHelper{
c: c,
contexts: contexts,
}
}
// This file is for the rendering of confirmation panels along with setting and handling associated
// keybindings.
func (self *ConfirmationHelper) wrappedConfirmationFunction(cancel goContext.CancelFunc, function func() error) func() error {
return func() error {
cancel()
if err := self.c.PopContext(); err != nil {
return err
}
if function != nil {
if err := function(); err != nil {
return self.c.Error(err)
}
}
return nil
}
}
func (self *ConfirmationHelper) wrappedPromptConfirmationFunction(cancel goContext.CancelFunc, function func(string) error, getResponse func() string) func() error {
return self.wrappedConfirmationFunction(cancel, func() error {
return function(getResponse())
})
}
func (self *ConfirmationHelper) DeactivateConfirmationPrompt() {
self.c.Mutexes().PopupMutex.Lock()
self.c.State().GetRepoState().SetCurrentPopupOpts(nil)
self.c.Mutexes().PopupMutex.Unlock()
self.c.Views().Confirmation.Visible = false
self.c.Views().Suggestions.Visible = false
self.clearConfirmationViewKeyBindings()
}
func getMessageHeight(wrap bool, message string, width int) int {
lines := strings.Split(message, "\n")
lineCount := 0
// if we need to wrap, calculate height to fit content within view's width
if wrap {
for _, line := range lines {
lineCount += runewidth.StringWidth(line)/width + 1
}
} else {
lineCount = len(lines)
}
return lineCount
}
func (self *ConfirmationHelper) getConfirmationPanelDimensions(wrap bool, prompt string) (int, int, int, int) {
panelWidth := self.getConfirmationPanelWidth()
panelHeight := getMessageHeight(wrap, prompt, panelWidth)
return self.getConfirmationPanelDimensionsAux(panelWidth, panelHeight)
}
func (self *ConfirmationHelper) getConfirmationPanelDimensionsForContentHeight(panelWidth, contentHeight int) (int, int, int, int) {
return self.getConfirmationPanelDimensionsAux(panelWidth, contentHeight)
}
func (self *ConfirmationHelper) getConfirmationPanelDimensionsAux(panelWidth int, panelHeight int) (int, int, int, int) {
width, height := self.c.GocuiGui().Size()
if panelHeight > height*3/4 {
panelHeight = height * 3 / 4
}
return width/2 - panelWidth/2,
height/2 - panelHeight/2 - panelHeight%2 - 1,
width/2 + panelWidth/2,
height/2 + panelHeight/2
}
func (self *ConfirmationHelper) getConfirmationPanelWidth() int {
width, _ := self.c.GocuiGui().Size()
// we want a minimum width up to a point, then we do it based on ratio.
panelWidth := 4 * width / 7
minWidth := 80
if panelWidth < minWidth {
if width-2 < minWidth {
panelWidth = width - 2
} else {
panelWidth = minWidth
}
}
return panelWidth
}
func (self *ConfirmationHelper) prepareConfirmationPanel(
ctx goContext.Context,
opts types.ConfirmOpts,
) error {
self.c.Views().Confirmation.HasLoader = opts.HasLoader
if opts.HasLoader {
self.c.GocuiGui().StartTicking(ctx)
}
self.c.Views().Confirmation.Title = opts.Title
// for now we do not support wrapping in our editor
self.c.Views().Confirmation.Wrap = !opts.Editable
self.c.Views().Confirmation.FgColor = theme.GocuiDefaultTextColor
self.c.Views().Confirmation.Mask = runeForMask(opts.Mask)
_ = self.c.Views().Confirmation.SetOrigin(0, 0)
suggestionsContext := self.contexts.Suggestions
suggestionsContext.State.FindSuggestions = opts.FindSuggestionsFunc
if opts.FindSuggestionsFunc != nil {
suggestionsView := self.c.Views().Suggestions
suggestionsView.Wrap = false
suggestionsView.FgColor = theme.GocuiDefaultTextColor
suggestionsContext.SetSuggestions(opts.FindSuggestionsFunc(""))
suggestionsView.Visible = true
suggestionsView.Title = fmt.Sprintf(self.c.Tr.SuggestionsTitle, self.c.UserConfig.Keybinding.Universal.TogglePanel)
}
self.ResizeConfirmationPanel()
return nil
}
func runeForMask(mask bool) rune {
if mask {
return '*'
}
return 0
}
func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts types.CreatePopupPanelOpts) error {
self.c.Mutexes().PopupMutex.Lock()
defer self.c.Mutexes().PopupMutex.Unlock()
ctx, cancel := goContext.WithCancel(ctx)
// we don't allow interruptions of non-loader popups in case we get stuck somehow
// e.g. a credentials popup never gets its required user input so a process hangs
// forever.
// The proper solution is to have a queue of popup options
currentPopupOpts := self.c.State().GetRepoState().GetCurrentPopupOpts()
if currentPopupOpts != nil && !currentPopupOpts.HasLoader {
self.c.Log.Error("ignoring create popup panel because a popup panel is already open")
cancel()
return nil
}
// remove any previous keybindings
self.clearConfirmationViewKeyBindings()
err := self.prepareConfirmationPanel(
ctx,
types.ConfirmOpts{
Title: opts.Title,
Prompt: opts.Prompt,
HasLoader: opts.HasLoader,
FindSuggestionsFunc: opts.FindSuggestionsFunc,
Editable: opts.Editable,
Mask: opts.Mask,
})
if err != nil {
cancel()
return err
}
confirmationView := self.c.Views().Confirmation
confirmationView.Editable = opts.Editable
if opts.Editable {
textArea := confirmationView.TextArea
textArea.Clear()
textArea.TypeString(opts.Prompt)
self.ResizeConfirmationPanel()
confirmationView.RenderTextArea()
} else {
self.c.ResetViewOrigin(confirmationView)
self.c.SetViewContent(confirmationView, style.AttrBold.Sprint(opts.Prompt))
}
if err := self.setKeyBindings(cancel, opts); err != nil {
cancel()
return err
}
self.c.State().GetRepoState().SetCurrentPopupOpts(&opts)
return self.c.PushContext(self.contexts.Confirmation)
}
func (self *ConfirmationHelper) setKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) error {
var onConfirm func() error
if opts.HandleConfirmPrompt != nil {
onConfirm = self.wrappedPromptConfirmationFunction(cancel, opts.HandleConfirmPrompt, func() string { return self.c.Views().Confirmation.TextArea.GetContent() })
} else {
onConfirm = self.wrappedConfirmationFunction(cancel, opts.HandleConfirm)
}
onSuggestionConfirm := self.wrappedPromptConfirmationFunction(
cancel,
opts.HandleConfirmPrompt,
self.getSelectedSuggestionValue,
)
onClose := self.wrappedConfirmationFunction(cancel, opts.HandleClose)
self.contexts.Confirmation.State.OnConfirm = onConfirm
self.contexts.Confirmation.State.OnClose = onClose
self.contexts.Suggestions.State.OnConfirm = onSuggestionConfirm
self.contexts.Suggestions.State.OnClose = onClose
return nil
}
func (self *ConfirmationHelper) clearConfirmationViewKeyBindings() {
noop := func() error { return nil }
self.contexts.Confirmation.State.OnConfirm = noop
self.contexts.Confirmation.State.OnClose = noop
self.contexts.Suggestions.State.OnConfirm = noop
self.contexts.Suggestions.State.OnClose = noop
}
func (self *ConfirmationHelper) getSelectedSuggestionValue() string {
selectedSuggestion := self.contexts.Suggestions.GetSelected()
if selectedSuggestion != nil {
return selectedSuggestion.Value
}
return ""
}
func (self *ConfirmationHelper) ResizeConfirmationPanel() {
suggestionsViewHeight := 0
if self.c.Views().Suggestions.Visible {
suggestionsViewHeight = 11
}
panelWidth := self.getConfirmationPanelWidth()
prompt := self.c.Views().Confirmation.Buffer()
wrap := true
if self.c.Views().Confirmation.Editable {
prompt = self.c.Views().Confirmation.TextArea.GetContent()
wrap = false
}
panelHeight := getMessageHeight(wrap, prompt, panelWidth) + suggestionsViewHeight
x0, y0, x1, y1 := self.getConfirmationPanelDimensionsAux(panelWidth, panelHeight)
confirmationViewBottom := y1 - suggestionsViewHeight
_, _ = self.c.GocuiGui().SetView(self.c.Views().Confirmation.Name(), x0, y0, x1, confirmationViewBottom, 0)
suggestionsViewTop := confirmationViewBottom + 1
_, _ = self.c.GocuiGui().SetView(self.c.Views().Suggestions.Name(), x0, suggestionsViewTop, x1, suggestionsViewTop+suggestionsViewHeight, 0)
}
func (self *ConfirmationHelper) ResizeCurrentPopupPanel() error {
v := self.c.GocuiGui().CurrentView()
if v == nil {
return nil
}
if v == self.c.Views().Menu {
self.resizeMenu()
} else if v == self.c.Views().Confirmation || v == self.c.Views().Suggestions {
self.ResizeConfirmationPanel()
} else if self.IsPopupPanel(v.Name()) {
return self.ResizePopupPanel(v, v.Buffer())
}
return nil
}
func (self *ConfirmationHelper) ResizePopupPanel(v *gocui.View, content string) error {
x0, y0, x1, y1 := self.getConfirmationPanelDimensions(v.Wrap, content)
_, err := self.c.GocuiGui().SetView(v.Name(), x0, y0, x1, y1, 0)
return err
}
func (self *ConfirmationHelper) resizeMenu() {
itemCount := self.contexts.Menu.GetList().Len()
offset := 3
panelWidth := self.getConfirmationPanelWidth()
x0, y0, x1, y1 := self.getConfirmationPanelDimensionsForContentHeight(panelWidth, itemCount+offset)
menuBottom := y1 - offset
_, _ = self.c.GocuiGui().SetView(self.c.Views().Menu.Name(), x0, y0, x1, menuBottom, 0)
tooltipTop := menuBottom + 1
tooltipHeight := getMessageHeight(true, self.contexts.Menu.GetSelected().Tooltip, panelWidth) + 2 // plus 2 for the frame
_, _ = self.c.GocuiGui().SetView(self.c.Views().Tooltip.Name(), x0, tooltipTop, x1, tooltipTop+tooltipHeight-1, 0)
}
func (self *ConfirmationHelper) IsPopupPanel(viewName string) bool {
return viewName == "commitMessage" || viewName == "confirmation" || viewName == "menu"
}
func (self *ConfirmationHelper) IsPopupPanelFocused() bool {
return self.IsPopupPanel(self.c.CurrentContext().GetViewName())
}

View File

@ -25,6 +25,7 @@ type Helpers struct {
Window *WindowHelper
View *ViewHelper
Refresh *RefreshHelper
Confirmation *ConfirmationHelper
}
func NewStubHelpers() *Helpers {
@ -52,5 +53,6 @@ func NewStubHelpers() *Helpers {
Window: &WindowHelper{},
View: &ViewHelper{},
Refresh: &RefreshHelper{},
Confirmation: &ConfirmationHelper{},
}
}

View File

@ -1,11 +1,8 @@
package helpers
import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -27,18 +24,6 @@ func NewMergeConflictsHelper(
}
}
func (self *MergeConflictsHelper) GetMergingOptions() map[string]string {
keybindingConfig := self.c.UserConfig.Keybinding
return map[string]string{
fmt.Sprintf("%s %s", keybindings.Label(keybindingConfig.Universal.PrevItem), keybindings.Label(keybindingConfig.Universal.NextItem)): self.c.Tr.LcSelectHunk,
fmt.Sprintf("%s %s", keybindings.Label(keybindingConfig.Universal.PrevBlock), keybindings.Label(keybindingConfig.Universal.NextBlock)): self.c.Tr.LcNavigateConflicts,
keybindings.Label(keybindingConfig.Universal.Select): self.c.Tr.LcPickHunk,
keybindings.Label(keybindingConfig.Main.PickBothHunks): self.c.Tr.LcPickAllHunks,
keybindings.Label(keybindingConfig.Universal.Undo): self.c.Tr.LcUndo,
}
}
func (self *MergeConflictsHelper) SetMergeState(path string) (bool, error) {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()

View File

@ -6,6 +6,7 @@ import (
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
@ -35,8 +36,8 @@ type ISuggestionsHelper interface {
type SuggestionsHelper struct {
c *types.HelperCommon
model *types.Model
refreshSuggestionsFn func()
model *types.Model
contexts *context.ContextTree
}
var _ ISuggestionsHelper = &SuggestionsHelper{}
@ -44,12 +45,12 @@ var _ ISuggestionsHelper = &SuggestionsHelper{}
func NewSuggestionsHelper(
c *types.HelperCommon,
model *types.Model,
refreshSuggestionsFn func(),
contexts *context.ContextTree,
) *SuggestionsHelper {
return &SuggestionsHelper{
c: c,
model: model,
refreshSuggestionsFn: refreshSuggestionsFn,
c: c,
model: model,
contexts: contexts,
}
}
@ -127,7 +128,7 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type
// cache the trie for future use
self.model.FilesTrie = trie
self.refreshSuggestionsFn()
self.contexts.Suggestions.RefreshSuggestions()
return err
})

View File

@ -28,12 +28,16 @@ func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types.
Handler: self.press,
},
{
Key: opts.GetKey(opts.Config.Universal.Confirm),
Handler: self.press,
Key: opts.GetKey(opts.Config.Universal.Confirm),
Handler: self.press,
Description: self.c.Tr.LcExecute,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: self.close,
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: self.close,
Description: self.c.Tr.LcClose,
Display: true,
},
}

View File

@ -41,21 +41,25 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts)
Key: opts.GetKey(opts.Config.Universal.PrevBlock),
Handler: self.withRenderAndFocus(self.PrevConflict),
Description: self.c.Tr.PrevConflict,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Universal.NextBlock),
Handler: self.withRenderAndFocus(self.NextConflict),
Description: self.c.Tr.NextConflict,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Universal.PrevItem),
Handler: self.withRenderAndFocus(self.PrevConflictHunk),
Description: self.c.Tr.SelectPrevHunk,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Universal.NextItem),
Handler: self.withRenderAndFocus(self.NextConflictHunk),
Description: self.c.Tr.SelectNextHunk,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt),
@ -89,6 +93,7 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts)
Key: opts.GetKey(opts.Config.Universal.Undo),
Handler: self.withRenderAndFocus(self.HandleUndo),
Description: self.c.Tr.LcUndo,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Files.OpenMergeTool),
@ -99,11 +104,13 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts)
Key: opts.GetKey(opts.Config.Universal.Select),
Handler: self.withRenderAndFocus(self.HandlePickHunk),
Description: self.c.Tr.PickHunk,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Main.PickBothHunks),
Handler: self.withRenderAndFocus(self.HandlePickAllHunks),
Description: self.c.Tr.PickAllHunks,
Display: true,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),

View File

@ -59,6 +59,27 @@ func (self *PatchBuildingController) GetMouseKeybindings(opts types.KeybindingsO
return []*gocui.ViewMouseBinding{}
}
func (self *PatchBuildingController) GetOnFocus() func(types.OnFocusOpts) error {
return func(opts types.OnFocusOpts) error {
// no need to change wrap on the secondary view because it can't be interacted with
self.c.Views().PatchBuilding.Wrap = false
return self.helpers.PatchBuilding.RefreshPatchBuildingPanel(opts)
}
}
func (self *PatchBuildingController) GetOnFocusLost() func(types.OnFocusLostOpts) error {
return func(opts types.OnFocusLostOpts) error {
self.c.Views().PatchBuilding.Wrap = true
if self.git.Patch.PatchBuilder.IsEmpty() {
self.git.Patch.PatchBuilder.Reset()
}
return nil
}
}
func (self *PatchBuildingController) OpenFile() error {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()

View File

@ -99,6 +99,29 @@ func (self *StagingController) GetMouseKeybindings(opts types.KeybindingsOpts) [
return []*gocui.ViewMouseBinding{}
}
func (self *StagingController) GetOnFocus() func(types.OnFocusOpts) error {
return func(opts types.OnFocusOpts) error {
self.c.Views().Staging.Wrap = false
self.c.Views().StagingSecondary.Wrap = false
return self.helpers.Staging.RefreshStagingPanel(opts)
}
}
func (self *StagingController) GetOnFocusLost() func(types.OnFocusLostOpts) error {
return func(opts types.OnFocusLostOpts) error {
self.context.SetState(nil)
if opts.NewContextKey != self.otherContext.GetKey() {
self.c.Views().Staging.Wrap = true
self.c.Views().StagingSecondary.Wrap = true
_ = self.contexts.Staging.Render(false)
_ = self.contexts.StagingSecondary.Render(false)
}
return nil
}
}
func (self *StagingController) OpenFile() error {
self.context.GetMutex().Lock()
defer self.context.GetMutex().Unlock()

View File

@ -53,8 +53,8 @@ func (self *SubCommitsController) GetOnRenderToMain() func() error {
}
}
func (self *SubCommitsController) GetOnFocus() func() error {
return func() error {
func (self *SubCommitsController) GetOnFocus() func(types.OnFocusOpts) error {
return func(types.OnFocusOpts) error {
context := self.context
if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() {
context.SetLimitCommits(false)

View File

@ -22,14 +22,27 @@ func NewSuggestionsController(
}
func (self *SuggestionsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
bindings := []*types.Binding{}
bindings := []*types.Binding{
{
Key: opts.GetKey(opts.Config.Universal.Confirm),
Handler: func() error { return self.context().State.OnConfirm() },
},
{
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: func() error { return self.context().State.OnClose() },
},
{
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
Handler: func() error { return self.c.ReplaceContext(self.contexts.Confirmation) },
},
}
return bindings
}
func (self *SuggestionsController) GetOnFocusLost() func(types.OnFocusLostOpts) error {
return func(types.OnFocusLostOpts) error {
deactivateConfirmationPrompt
self.helpers.Confirmation.DeactivateConfirmationPrompt()
return nil
}
}

View File

@ -71,12 +71,12 @@ func (gui *Gui) commitMessageEditor(v *gocui.View, key gocui.Key, ch rune, mod g
// This function is called again on refresh as part of the general resize popup call,
// but we need to call it here so that when we go to render the text area it's not
// considered out of bounds to add a newline, meaning we can avoid unnecessary scrolling.
err := gui.resizePopupPanel(v, v.TextArea.GetContent())
err := gui.helpers.Confirmation.ResizePopupPanel(v, v.TextArea.GetContent())
if err != nil {
gui.c.Log.Error(err)
}
v.RenderTextArea()
gui.RenderCommitLength()
gui.State.Contexts.CommitMessage.RenderCommitLength()
return matched
}
@ -86,11 +86,12 @@ func (gui *Gui) defaultEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.M
v.RenderTextArea()
if gui.findSuggestions != nil {
suggestionsContext := gui.State.Contexts.Suggestions
if suggestionsContext.State.FindSuggestions != nil {
input := v.TextArea.GetContent()
gui.suggestionsAsyncHandler.Do(func() func() {
suggestions := gui.findSuggestions(input)
return func() { gui.setSuggestions(suggestions) }
suggestionsContext.State.AsyncHandler.Do(func() func() {
suggestions := suggestionsContext.State.FindSuggestions(input)
return func() { suggestionsContext.SetSuggestions(suggestions) }
})
}

View File

@ -17,16 +17,6 @@ func (gui *Gui) validateNotInFilterMode() bool {
return true
}
func (gui *Gui) outsideFilterMode(f func() error) func() error {
return func() error {
if !gui.validateNotInFilterMode() {
return nil
}
return f()
}
}
func (gui *Gui) exitFilterMode() error {
return gui.clearFiltering()
}

View File

@ -1,6 +1,7 @@
package gui
import (
goContext "context"
"fmt"
"io"
"os"
@ -94,10 +95,6 @@ type Gui struct {
Mutexes types.Mutexes
// findSuggestions will take a string that the user has typed into a prompt
// and return a slice of suggestions which match that string.
findSuggestions func(string) []*types.Suggestion
// when you enter into a submodule we'll append the superproject's path to this array
// so that you can return to the superproject
RepoPathStack *utils.StringStack
@ -113,8 +110,6 @@ type Gui struct {
// the extras window contains things like the command log
ShowExtrasWindow bool
suggestionsAsyncHandler *tasks.AsyncHandler
PopupHandler types.IPopupHandler
IsNewRepo bool
@ -198,9 +193,6 @@ type GuiRepoState struct {
Model *types.Model
Modes *types.Modes
// Suggestions will sometimes appear when typing into a prompt
Suggestions []*types.Suggestion
SplitMainPanel bool
LimitCommits bool
@ -412,18 +404,17 @@ func NewGui(
initialDir string,
) (*Gui, error) {
gui := &Gui{
Common: cmn,
gitVersion: gitVersion,
Config: config,
Updater: updater,
statusManager: &statusManager{},
viewBufferManagerMap: map[string]*tasks.ViewBufferManager{},
viewPtmxMap: map[string]*os.File{},
showRecentRepos: showRecentRepos,
RepoPathStack: &utils.StringStack{},
RepoStateMap: map[Repo]*GuiRepoState{},
CmdLog: []string{},
suggestionsAsyncHandler: tasks.NewAsyncHandler(),
Common: cmn,
gitVersion: gitVersion,
Config: config,
Updater: updater,
statusManager: &statusManager{},
viewBufferManagerMap: map[string]*tasks.ViewBufferManager{},
viewPtmxMap: map[string]*os.File{},
showRecentRepos: showRecentRepos,
RepoPathStack: &utils.StringStack{},
RepoStateMap: map[Repo]*GuiRepoState{},
CmdLog: []string{},
// originally we could only hide the command log permanently via the config
// but now we do it via state. So we need to still support the config for the
@ -446,7 +437,9 @@ func NewGui(
gui.PopupHandler = popup.NewPopupHandler(
cmn,
gui.createPopupPanel,
func(ctx goContext.Context, opts types.CreatePopupPanelOpts) error {
return gui.helpers.Confirmation.CreatePopupPanel(ctx, opts)
},
func() error { return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) },
gui.popContext,
gui.currentContext,

View File

@ -144,3 +144,7 @@ func (self *guiCommon) MainViewPairs() types.MainViewPairs {
func (self *guiCommon) State() types.IStateAccessor {
return self.gui.stateAccessor
}
func (self *guiCommon) KeybindingsOpts() types.KeybindingsOpts {
return self.gui.keybindingOpts()
}

View File

@ -50,7 +50,7 @@ func (self *GuiDriver) CurrentContext() types.Context {
}
func (self *GuiDriver) ContextForView(viewName string) types.Context {
context, ok := self.gui.contextForView(viewName)
context, ok := self.gui.helpers.View.ContextForView(viewName)
if !ok {
return nil
}

View File

@ -11,7 +11,17 @@ import (
func (gui *Gui) noPopupPanel(f func() error) func() error {
return func() error {
if gui.popupPanelFocused() {
if gui.helpers.Confirmation.IsPopupPanelFocused() {
return nil
}
return f()
}
}
func (gui *Gui) outsideFilterMode(f func() error) func() error {
return func() error {
if !gui.validateNotInFilterMode() {
return nil
}
@ -34,8 +44,7 @@ func (self *Gui) GetCheatsheetKeybindings() []*types.Binding {
return bindings
}
// renaming receiver to 'self' to aid refactoring. Will probably end up moving all Gui handlers to this pattern eventually.
func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) {
func (self *Gui) keybindingOpts() types.KeybindingsOpts {
config := self.c.UserConfig.Keybinding
guards := types.KeybindingGuards{
@ -43,11 +52,18 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
NoPopupPanel: self.noPopupPanel,
}
opts := types.KeybindingsOpts{
return types.KeybindingsOpts{
GetKey: keybindings.GetKey,
Config: config,
Guards: guards,
}
}
// renaming receiver to 'self' to aid refactoring. Will probably end up moving all Gui handlers to this pattern eventually.
func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) {
config := self.c.UserConfig.Keybinding
opts := self.c.KeybindingsOpts()
bindings := []*types.Binding{
{
@ -486,7 +502,7 @@ func (gui *Gui) SetKeybinding(binding *types.Binding) error {
if gocui.IsMouseKey(binding.Key) {
handler = func() error {
// we ignore click events on views that aren't popup panels, when a popup panel is focused
if gui.popupPanelFocused() && gui.currentViewName() != binding.ViewName {
if gui.helpers.Confirmation.IsPopupPanelFocused() && gui.currentViewName() != binding.ViewName {
return nil
}
@ -502,7 +518,7 @@ func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error {
baseHandler := binding.Handler
newHandler := func(opts gocui.ViewMouseBindingOpts) error {
// we ignore click events on views that aren't popup panels, when a popup panel is focused
if gui.popupPanelFocused() && gui.currentViewName() != binding.ViewName {
if gui.helpers.Confirmation.IsPopupPanelFocused() && gui.currentViewName() != binding.ViewName {
return nil
}

View File

@ -163,7 +163,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
// if you run `lazygit --logs`
// this will let you see these branches as prettified json
// gui.c.Log.Info(utils.AsJson(gui.State.Model.Branches[0:4]))
return gui.resizeCurrentPopupPanel()
return gui.helpers.Confirmation.ResizeCurrentPopupPanel()
}
func (gui *Gui) prepareView(viewName string) (*gocui.View, error) {
@ -245,7 +245,7 @@ func (gui *Gui) getFocusLayout() func(g *gocui.Gui) error {
return func(g *gocui.Gui) error {
newView := gui.g.CurrentView()
// for now we don't consider losing focus to a popup panel as actually losing focus
if newView != previousView && !gui.isPopupPanel(newView.Name()) {
if newView != previousView && !gui.helpers.Confirmation.IsPopupPanel(newView.Name()) {
if err := gui.onViewFocusLost(previousView); err != nil {
return err
}

View File

@ -14,14 +14,7 @@ import (
)
func (gui *Gui) menuListContext() *context.MenuContext {
return context.NewMenuContext(
gui.Views.Menu,
gui.c,
gui.getMenuOptions,
func(content string) {
gui.Views.Tooltip.SetContent(content)
},
)
return context.NewMenuContext(gui.c)
}
func (gui *Gui) filesListContext() *context.WorkingTreeContext {
@ -237,14 +230,7 @@ func (gui *Gui) submodulesListContext() *context.SubmodulesContext {
}
func (gui *Gui) suggestionsListContext() *context.SuggestionsContext {
return context.NewSuggestionsContext(
func() []*types.Suggestion { return gui.State.Suggestions },
gui.Views.Suggestions,
func(startIdx int, length int) [][]string {
return presentation.GetSuggestionListDisplayStrings(gui.State.Suggestions)
},
gui.c,
)
return context.NewSuggestionsContext(gui.c)
}
func (gui *Gui) getListContexts() []types.IListContext {

View File

@ -1,25 +1,12 @@
package gui
import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils"
)
func (gui *Gui) getMenuOptions() map[string]string {
keybindingConfig := gui.c.UserConfig.Keybinding
return map[string]string{
keybindings.Label(keybindingConfig.Universal.Return): gui.c.Tr.LcClose,
fmt.Sprintf("%s %s", keybindings.Label(keybindingConfig.Universal.PrevItem), keybindings.Label(keybindingConfig.Universal.NextItem)): gui.c.Tr.LcNavigate,
keybindings.Label(keybindingConfig.Universal.Select): gui.c.Tr.LcExecute,
}
}
// note: items option is mutated by this function
func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
if !opts.HideCancel {

View File

@ -2,12 +2,11 @@ package gui
import (
"fmt"
"sort"
"strings"
"github.com/jesseduffield/generics/maps"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
type OptionsMapMgr struct {
@ -21,36 +20,73 @@ func (gui *Gui) renderContextOptionsMap(c types.Context) {
// render the options available for the current context at the bottom of the screen
func (self *OptionsMapMgr) renderContextOptionsMap(c types.Context) {
optionsMap := c.GetOptionsMap()
if optionsMap == nil {
optionsMap = self.globalOptionsMap()
bindingsToDisplay := lo.Filter(c.GetKeybindings(self.c.KeybindingsOpts()), func(binding *types.Binding, _ int) bool {
return binding.Display
})
var optionsMap []bindingInfo
if len(bindingsToDisplay) == 0 {
optionsMap = self.globalOptions()
} else {
optionsMap = lo.Map(bindingsToDisplay, func(binding *types.Binding, _ int) bindingInfo {
return bindingInfo{
key: keybindings.LabelFromKey(binding.Key),
description: binding.Description,
}
})
}
self.renderOptions(self.optionsMapToString(optionsMap))
self.renderOptions(self.formatBindingInfos(optionsMap))
}
func (self *OptionsMapMgr) optionsMapToString(optionsMap map[string]string) string {
options := maps.MapToSlice(optionsMap, func(key string, description string) string {
return key + ": " + description
})
sort.Strings(options)
return strings.Join(options, ", ")
func (self *OptionsMapMgr) formatBindingInfos(bindingInfos []bindingInfo) string {
return strings.Join(
lo.Map(bindingInfos, func(bindingInfo bindingInfo, _ int) string {
return fmt.Sprintf("%s: %s", bindingInfo.key, bindingInfo.description)
}),
", ")
}
func (self *OptionsMapMgr) renderOptions(options string) {
self.c.SetViewContent(self.c.Views().Options, options)
}
func (self *OptionsMapMgr) globalOptionsMap() map[string]string {
func (self *OptionsMapMgr) globalOptions() []bindingInfo {
keybindingConfig := self.c.UserConfig.Keybinding
return map[string]string{
fmt.Sprintf("%s/%s", keybindings.Label(keybindingConfig.Universal.ScrollUpMain), keybindings.Label(keybindingConfig.Universal.ScrollDownMain)): self.c.Tr.LcScroll,
fmt.Sprintf("%s %s %s %s", keybindings.Label(keybindingConfig.Universal.PrevBlock), keybindings.Label(keybindingConfig.Universal.NextBlock), keybindings.Label(keybindingConfig.Universal.PrevItem), keybindings.Label(keybindingConfig.Universal.NextItem)): self.c.Tr.LcNavigate,
keybindings.Label(keybindingConfig.Universal.Return): self.c.Tr.LcCancel,
keybindings.Label(keybindingConfig.Universal.Quit): self.c.Tr.LcQuit,
keybindings.Label(keybindingConfig.Universal.OptionMenuAlt1): self.c.Tr.LcMenu,
fmt.Sprintf("%s-%s", keybindings.Label(keybindingConfig.Universal.JumpToBlock[0]), keybindings.Label(keybindingConfig.Universal.JumpToBlock[len(keybindingConfig.Universal.JumpToBlock)-1])): self.c.Tr.LcJump,
fmt.Sprintf("%s/%s", keybindings.Label(keybindingConfig.Universal.ScrollLeft), keybindings.Label(keybindingConfig.Universal.ScrollRight)): self.c.Tr.LcScrollLeftRight,
return []bindingInfo{
{
key: fmt.Sprintf("%s/%s", keybindings.Label(keybindingConfig.Universal.ScrollUpMain), keybindings.Label(keybindingConfig.Universal.ScrollDownMain)),
description: self.c.Tr.LcScroll,
},
{
key: fmt.Sprintf("%s %s %s %s", keybindings.Label(keybindingConfig.Universal.PrevBlock), keybindings.Label(keybindingConfig.Universal.NextBlock), keybindings.Label(keybindingConfig.Universal.PrevItem), keybindings.Label(keybindingConfig.Universal.NextItem)),
description: self.c.Tr.LcNavigate,
},
{
key: keybindings.Label(keybindingConfig.Universal.Return),
description: self.c.Tr.LcCancel,
},
{
key: keybindings.Label(keybindingConfig.Universal.Quit),
description: self.c.Tr.LcQuit,
},
{
key: keybindings.Label(keybindingConfig.Universal.OptionMenuAlt1),
description: self.c.Tr.LcMenu,
},
{
key: fmt.Sprintf("%s-%s", keybindings.Label(keybindingConfig.Universal.JumpToBlock[0]), keybindings.Label(keybindingConfig.Universal.JumpToBlock[len(keybindingConfig.Universal.JumpToBlock)-1])),
description: self.c.Tr.LcJump,
},
{
key: fmt.Sprintf("%s/%s", keybindings.Label(keybindingConfig.Universal.ScrollLeft), keybindings.Label(keybindingConfig.Universal.ScrollRight)),
description: self.c.Tr.LcScrollLeftRight,
},
}
}
type bindingInfo struct {
key string
description string
}

View File

@ -1,26 +0,0 @@
package gui
import (
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
func (gui *Gui) getSelectedSuggestionValue() string {
selectedSuggestion := gui.getSelectedSuggestion()
if selectedSuggestion != nil {
return selectedSuggestion.Value
}
return ""
}
func (gui *Gui) getSelectedSuggestion() *types.Suggestion {
return gui.State.Contexts.Suggestions.GetSelected()
}
func (gui *Gui) setSuggestions(suggestions []*types.Suggestion) {
gui.State.Suggestions = suggestions
gui.State.Contexts.Suggestions.SetSelectedLineIdx(0)
gui.c.ResetViewOrigin(gui.Views.Suggestions)
_ = gui.State.Contexts.Suggestions.HandleRender()
}

View File

@ -82,6 +82,8 @@ type IGuiCommon interface {
Mutexes() Mutexes
State() IStateAccessor
KeybindingsOpts() KeybindingsOpts
}
type IPopupHandler interface {

View File

@ -17,6 +17,12 @@ type Binding struct {
Tag string // e.g. 'navigation'. Used for grouping things in the cheatsheet
OpensMenu bool
// If true, the keybinding will appear at the bottom of the screen. If
// the given view has no bindings with Display: true, the default keybindings
// will be displayed instead.
// TODO: implement this
Display bool
// to be displayed if the keybinding is highlighted from within a menu
Tooltip string
}

View File

@ -62,71 +62,6 @@ func (gui *Gui) currentViewName() string {
return currentView.Name()
}
func (gui *Gui) resizeCurrentPopupPanel() error {
v := gui.g.CurrentView()
if v == nil {
return nil
}
if v == gui.Views.Menu {
gui.resizeMenu()
} else if v == gui.Views.Confirmation || v == gui.Views.Suggestions {
gui.resizeConfirmationPanel()
} else if gui.isPopupPanel(v.Name()) {
return gui.resizePopupPanel(v, v.Buffer())
}
return nil
}
func (gui *Gui) resizePopupPanel(v *gocui.View, content string) error {
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(v.Wrap, content)
_, err := gui.g.SetView(v.Name(), x0, y0, x1, y1, 0)
return err
}
func (gui *Gui) resizeMenu() {
itemCount := gui.State.Contexts.Menu.GetList().Len()
offset := 3
panelWidth := gui.getConfirmationPanelWidth()
x0, y0, x1, y1 := gui.getConfirmationPanelDimensionsForContentHeight(panelWidth, itemCount+offset)
menuBottom := y1 - offset
_, _ = gui.g.SetView(gui.Views.Menu.Name(), x0, y0, x1, menuBottom, 0)
tooltipTop := menuBottom + 1
tooltipHeight := gui.getMessageHeight(true, gui.State.Contexts.Menu.GetSelected().Tooltip, panelWidth) + 2 // plus 2 for the frame
_, _ = gui.g.SetView(gui.Views.Tooltip.Name(), x0, tooltipTop, x1, tooltipTop+tooltipHeight-1, 0)
}
func (gui *Gui) resizeConfirmationPanel() {
suggestionsViewHeight := 0
if gui.Views.Suggestions.Visible {
suggestionsViewHeight = 11
}
panelWidth := gui.getConfirmationPanelWidth()
prompt := gui.Views.Confirmation.Buffer()
wrap := true
if gui.Views.Confirmation.Editable {
prompt = gui.Views.Confirmation.TextArea.GetContent()
wrap = false
}
panelHeight := gui.getMessageHeight(wrap, prompt, panelWidth) + suggestionsViewHeight
x0, y0, x1, y1 := gui.getConfirmationPanelDimensionsAux(panelWidth, panelHeight)
confirmationViewBottom := y1 - suggestionsViewHeight
_, _ = gui.g.SetView(gui.Views.Confirmation.Name(), x0, y0, x1, confirmationViewBottom, 0)
suggestionsViewTop := confirmationViewBottom + 1
_, _ = gui.g.SetView(gui.Views.Suggestions.Name(), x0, suggestionsViewTop, x1, suggestionsViewTop+suggestionsViewHeight, 0)
}
func (gui *Gui) isPopupPanel(viewName string) bool {
return viewName == "commitMessage" || viewName == "confirmation" || viewName == "menu"
}
func (gui *Gui) popupPanelFocused() bool {
return gui.isPopupPanel(gui.currentViewName())
}
func (gui *Gui) onViewTabClick(windowName string, tabIndex int) error {
tabs := gui.viewTabMap()[windowName]
if len(tabs) == 0 {

View File

@ -156,6 +156,7 @@ func (gui *Gui) createAllViews() error {
gui.Views.CommitMessage.Editor = gocui.EditorFunc(gui.commitMessageEditor)
gui.Views.Confirmation.Visible = false
gui.Views.Confirmation.Editor = gocui.EditorFunc(gui.defaultEditor)
gui.Views.Suggestions.Visible = false

View File

@ -94,9 +94,9 @@ func chineseTranslationSet() TranslationSet {
LcNewBranch: "新分支",
LcDeleteBranch: "删除分支",
NoBranchesThisRepo: "此仓库中没有分支",
CommitMessageConfirm: "{{.keyBindClose}}:关闭,{{.keyBindNewLine}}:新行,{{.keyBindConfirm}}:确认",
CommitWithoutMessageErr: "您必须编写提交消息才能进行提交",
CloseConfirm: "{{.keyBindClose}}:关闭,{{.keyBindConfirm}}:确认",
LcCloseCancel: "关闭",
LcConfirm: "确认",
LcClose: "关闭",
LcQuit: "退出",
LcSquashDown: "向下压缩",
@ -117,8 +117,6 @@ func chineseTranslationSet() TranslationSet {
LcAmendToCommit: "用已暂存的更改来修补提交",
LcRenameCommitEditor: "使用编辑器重命名提交",
Error: "错误",
LcSelectHunk: "切换区块",
LcNavigateConflicts: "浏览冲突",
LcPickHunk: "选中区块",
LcPickAllHunks: "选中所有区块",
LcUndo: "撤销",

View File

@ -60,9 +60,9 @@ func dutchTranslationSet() TranslationSet {
LcNewBranch: "nieuwe branch",
LcDeleteBranch: "verwijder branch",
NoBranchesThisRepo: "Geen branches voor deze repo",
CommitMessageConfirm: "{{.keyBindClose}}: Sluiten, {{.keyBindNewLine}}: Nieuwe lijn, {{.keyBindConfirm}}: Bevestig",
CommitWithoutMessageErr: "Je kan geen commit maken zonder commit bericht",
CloseConfirm: "{{.keyBindClose}}: Sluiten, {{.keyBindConfirm}}: Bevestig",
LcCloseCancel: "sluiten",
LcConfirm: "bevestig",
LcClose: "sluiten",
LcQuit: "quit",
LcSquashDown: "squash beneden",
@ -83,8 +83,6 @@ func dutchTranslationSet() TranslationSet {
LcRenameCommitEditor: "hernoem commit met editor",
NoCommitsThisBranch: "Geen commits in deze branch",
Error: "Foutmelding",
LcSelectHunk: "selecteer stuk",
LcNavigateConflicts: "navigeer conflicts",
LcPickHunk: "kies stuk",
LcPickAllHunks: "kies beide stukken",
LcUndo: "ongedaan maken",

View File

@ -80,10 +80,10 @@ type TranslationSet struct {
LcNewBranch string
LcDeleteBranch string
NoBranchesThisRepo string
CommitMessageConfirm string
CommitWithoutMessageErr string
CloseConfirm string
LcClose string
LcCloseCancel string
LcConfirm string
LcQuit string
LcSquashDown string
LcFixupCommit string
@ -107,8 +107,6 @@ type TranslationSet struct {
NoCommitsThisBranch string
UpdateRefHere string
Error string
LcSelectHunk string
LcNavigateConflicts string
LcPickHunk string
LcPickAllHunks string
LcUndo string
@ -750,10 +748,10 @@ func EnglishTranslationSet() TranslationSet {
LcNewBranch: "new branch",
LcDeleteBranch: "delete branch",
NoBranchesThisRepo: "No branches for this repo",
CommitMessageConfirm: "{{.keyBindClose}}: close, {{.keyBindNewLine}}: new line, {{.keyBindConfirm}}: confirm",
CommitWithoutMessageErr: "You cannot commit without a commit message",
CloseConfirm: "{{.keyBindClose}}: close/cancel, {{.keyBindConfirm}}: confirm",
LcClose: "close",
LcCloseCancel: "close/cancel",
LcConfirm: "confirm",
LcQuit: "quit",
LcSquashDown: "squash down",
LcFixupCommit: "fixup commit",
@ -777,8 +775,6 @@ func EnglishTranslationSet() TranslationSet {
SureResetCommitAuthor: "The author field of this commit will be updated to match the configured user. This also renews the author timestamp. Continue?",
LcRenameCommitEditor: "reword commit with editor",
Error: "Error",
LcSelectHunk: "select hunk",
LcNavigateConflicts: "navigate conflicts",
LcPickHunk: "pick hunk",
LcPickAllHunks: "pick all hunks",
LcUndo: "undo",

View File

@ -85,9 +85,9 @@ func japaneseTranslationSet() TranslationSet {
LcNewBranch: "新しいブランチを作成",
LcDeleteBranch: "ブランチを削除",
NoBranchesThisRepo: "リポジトリにブランチが存在しません",
CommitMessageConfirm: "{{.keyBindClose}}: 閉じる, {{.keyBindNewLine}}: 改行, {{.keyBindConfirm}}: 確定",
CommitWithoutMessageErr: "コミットメッセージを入力してください",
CloseConfirm: "{{.keyBindClose}}: 閉じる/キャンセル, {{.keyBindConfirm}}: 確認",
LcCloseCancel: "閉じる/キャンセル",
LcConfirm: "確認",
LcClose: "閉じる",
LcQuit: "終了",
// LcSquashDown: "squash down",
@ -108,8 +108,6 @@ func japaneseTranslationSet() TranslationSet {
LcAmendToCommit: "ステージされた変更でamendコミット",
LcRenameCommitEditor: "エディタでコミットメッセージを編集",
Error: "エラー",
LcSelectHunk: "hunkを選択",
LcNavigateConflicts: "コンフリクトを移動",
// LcPickHunk: "pick hunk",
// LcPickAllHunks: "pick all hunks",
LcUndo: "アンドゥ",

View File

@ -84,9 +84,9 @@ func koreanTranslationSet() TranslationSet {
LcNewBranch: "새 브랜치 생성",
LcDeleteBranch: "브랜치 삭제",
NoBranchesThisRepo: "저장소에 브랜치가 존재하지 않습니다.",
CommitMessageConfirm: "{{.keyBindClose}}: 닫기, {{.keyBindNewLine}}: 개행, {{.keyBindConfirm}}: 확인",
CommitWithoutMessageErr: "커밋 메시지를 입력하세요.",
CloseConfirm: "{{.keyBindClose}}: 닫기/취소, {{.keyBindConfirm}}: 확인",
LcCloseCancel: "닫기/취소",
LcConfirm: "확인",
LcClose: "닫기",
LcQuit: "종료",
LcSquashDown: "squash down",
@ -109,8 +109,6 @@ func koreanTranslationSet() TranslationSet {
SureResetCommitAuthor: "The author field of this commit will be updated to match the configured user. This also renews the author timestamp. Continue?",
LcRenameCommitEditor: "에디터에서 커밋메시지 수정",
Error: "오류",
LcSelectHunk: "hunk를 선택",
LcNavigateConflicts: "navigate conflicts",
LcPickHunk: "pick hunk",
LcPickAllHunks: "pick all hunks",
LcUndo: "되돌리기",

View File

@ -55,9 +55,9 @@ func polishTranslationSet() TranslationSet {
LcNewBranch: "nowa gałąź",
LcDeleteBranch: "usuń gałąź",
NoBranchesThisRepo: "Brak gałęzi dla tego repozytorium",
CommitMessageConfirm: "{{.keyBindClose}}: zamknij, {{.keyBindNewLine}}: nowa linia, {{.keyBindConfirm}}: potwierdź",
CommitWithoutMessageErr: "Nie możesz commitować bez komunikatu",
CloseConfirm: "{{.keyBindClose}}: zamknij, {{.keyBindConfirm}}: potwierdź",
LcCloseCancel: "zamknij",
LcConfirm: "potwierdź",
LcClose: "zamknij",
LcSquashDown: "ściśnij",
LcFixupCommit: "napraw commit",
@ -68,8 +68,6 @@ func polishTranslationSet() TranslationSet {
LcRewordCommit: "zmień nazwę commita",
LcRenameCommitEditor: "zmień nazwę commita w edytorze",
Error: "Błąd",
LcSelectHunk: "wybierz kawałek",
LcNavigateConflicts: "nawiguj konflikty",
LcPickHunk: "wybierz kawałek",
LcPickAllHunks: "wybierz oba kawałki",
LcUndo: "cofnij",