1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-12 11:15:00 +02:00
lazygit/pkg/gui/confirmation_panel.go

183 lines
6.2 KiB
Go
Raw Normal View History

2018-05-26 05:23:39 +02:00
// lots of this has been directly ported from one of the example files, will brush up later
// Copyright 2014 The gocui Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
2018-08-14 11:05:26 +02:00
package gui
2018-05-26 05:23:39 +02:00
import (
2018-08-05 14:00:02 +02:00
"strings"
2018-12-05 10:33:46 +02:00
"time"
2018-05-26 05:23:39 +02:00
2018-08-05 14:00:02 +02:00
"github.com/fatih/color"
"github.com/jesseduffield/gocui"
2018-05-26 05:23:39 +02:00
)
2018-08-14 11:05:26 +02:00
func (gui *Gui) wrappedConfirmationFunction(function func(*gocui.Gui, *gocui.View) error) func(*gocui.Gui, *gocui.View) error {
2018-08-05 14:00:02 +02:00
return func(g *gocui.Gui, v *gocui.View) error {
if function != nil {
if err := function(g, v); err != nil {
2018-08-23 10:43:16 +02:00
return err
2018-08-05 14:00:02 +02:00
}
}
2018-08-14 11:05:26 +02:00
return gui.closeConfirmationPrompt(g)
2018-08-05 14:00:02 +02:00
}
2018-05-27 08:32:09 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) closeConfirmationPrompt(g *gocui.Gui) error {
2018-08-05 14:00:02 +02:00
view, err := g.View("confirmation")
if err != nil {
2018-12-07 09:52:31 +02:00
return nil // if it's already been closed we can just return
2018-08-05 14:00:02 +02:00
}
2018-08-14 11:05:26 +02:00
if err := gui.returnFocus(g, view); err != nil {
2018-08-05 14:00:02 +02:00
panic(err)
}
g.DeleteKeybindings("confirmation")
return g.DeleteView("confirmation")
2018-05-27 08:32:09 +02:00
}
func (gui *Gui) getMessageHeight(wrap bool, message string, width int) int {
2018-08-05 14:00:02 +02:00
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 += len(line)/width + 1
}
} else {
lineCount = len(lines)
2018-08-05 14:00:02 +02:00
}
return lineCount
2018-05-26 05:23:39 +02:00
}
func (gui *Gui) getConfirmationPanelDimensions(g *gocui.Gui, wrap bool, prompt string) (int, int, int, int) {
2018-08-05 14:00:02 +02:00
width, height := g.Size()
panelWidth := width / 2
panelHeight := gui.getMessageHeight(wrap, prompt, panelWidth)
2018-08-05 14:00:02 +02:00
return width/2 - panelWidth/2,
height/2 - panelHeight/2 - panelHeight%2 - 1,
width/2 + panelWidth/2,
height/2 + panelHeight/2
2018-05-26 05:23:39 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) createPromptPanel(g *gocui.Gui, currentView *gocui.View, title string, handleConfirm func(*gocui.Gui, *gocui.View) error) error {
2018-08-15 13:49:38 +02:00
gui.onNewPopupPanel()
2019-02-16 03:03:22 +02:00
confirmationView, err := gui.prepareConfirmationPanel(currentView, title, "", false)
2018-08-25 07:55:49 +02:00
if err != nil {
return err
}
confirmationView.Editable = true
return gui.setKeyBindings(g, handleConfirm, nil)
}
2019-02-16 03:03:22 +02:00
func (gui *Gui) prepareConfirmationPanel(currentView *gocui.View, title, prompt string, hasLoader bool) (*gocui.View, error) {
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(gui.g, true, prompt)
2018-08-25 07:55:49 +02:00
confirmationView, err := gui.g.SetView("confirmation", x0, y0, x1, y1, 0)
if err != nil {
2019-02-16 03:03:22 +02:00
if err.Error() != "unknown view" {
2018-08-25 07:55:49 +02:00
return nil, err
2018-08-05 14:00:02 +02:00
}
2019-02-16 03:03:22 +02:00
confirmationView.HasLoader = hasLoader
2018-08-05 14:00:02 +02:00
confirmationView.Title = title
2018-12-05 10:33:46 +02:00
confirmationView.Wrap = true
confirmationView.FgColor = gocui.ColorWhite
2018-08-05 14:00:02 +02:00
}
2018-12-07 09:52:31 +02:00
gui.g.Update(func(g *gocui.Gui) error {
return gui.switchFocus(gui.g, currentView, confirmationView)
})
2018-08-25 07:55:49 +02:00
return confirmationView, nil
2018-05-27 08:32:09 +02:00
}
2018-08-15 13:49:38 +02:00
func (gui *Gui) onNewPopupPanel() {
2019-02-11 12:07:12 +02:00
viewNames := []string{"commitMessage",
"credentials",
"menu"}
for _, viewName := range viewNames {
_, _ = gui.g.SetViewOnBottom(viewName)
}
2018-08-15 13:49:38 +02:00
}
2019-02-16 03:03:22 +02:00
func (gui *Gui) createLoaderPanel(g *gocui.Gui, currentView *gocui.View, prompt string) error {
return gui.createPopupPanel(g, currentView, "", prompt, true, nil, nil)
}
// it is very important that within this function we never include the original prompt in any error messages, because it may contain e.g. a user password
2018-08-14 11:05:26 +02:00
func (gui *Gui) createConfirmationPanel(g *gocui.Gui, currentView *gocui.View, title, prompt string, handleConfirm, handleClose func(*gocui.Gui, *gocui.View) error) error {
2019-02-16 03:03:22 +02:00
return gui.createPopupPanel(g, currentView, title, prompt, false, handleConfirm, handleClose)
}
func (gui *Gui) createPopupPanel(g *gocui.Gui, currentView *gocui.View, title, prompt string, hasLoader bool, handleConfirm, handleClose func(*gocui.Gui, *gocui.View) error) error {
2018-08-15 13:49:38 +02:00
gui.onNewPopupPanel()
2018-08-05 14:00:02 +02:00
g.Update(func(g *gocui.Gui) error {
// delete the existing confirmation panel if it exists
if view, _ := g.View("confirmation"); view != nil {
2018-08-14 11:05:26 +02:00
if err := gui.closeConfirmationPrompt(g); err != nil {
errMessage := gui.Tr.TemplateLocalize(
"CantCloseConfirmationPrompt",
Teml{
"error": err.Error(),
},
)
gui.Log.Error(errMessage)
2018-08-05 14:00:02 +02:00
}
}
2019-02-16 03:03:22 +02:00
confirmationView, err := gui.prepareConfirmationPanel(currentView, title, prompt, hasLoader)
2018-08-25 07:55:49 +02:00
if err != nil {
return err
2018-08-05 14:00:02 +02:00
}
2018-08-25 07:55:49 +02:00
confirmationView.Editable = false
if err := gui.renderString(g, "confirmation", prompt); err != nil {
return err
}
return gui.setKeyBindings(g, handleConfirm, handleClose)
2018-08-05 14:00:02 +02:00
})
return nil
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) setKeyBindings(g *gocui.Gui, handleConfirm, handleClose func(*gocui.Gui, *gocui.View) error) error {
actions := gui.Tr.TemplateLocalize(
"CloseConfirm",
Teml{
"keyBindClose": "esc",
"keyBindConfirm": "enter",
},
)
2018-08-25 07:55:49 +02:00
if err := gui.renderString(g, "options", actions); err != nil {
return err
}
2018-08-14 11:05:26 +02:00
if err := g.SetKeybinding("confirmation", gocui.KeyEnter, gocui.ModNone, gui.wrappedConfirmationFunction(handleConfirm)); err != nil {
2018-08-05 14:00:02 +02:00
return err
}
2018-08-14 11:05:26 +02:00
return g.SetKeybinding("confirmation", gocui.KeyEsc, gocui.ModNone, gui.wrappedConfirmationFunction(handleClose))
2018-05-26 05:23:39 +02:00
}
2018-05-27 08:32:09 +02:00
2018-08-14 11:05:26 +02:00
func (gui *Gui) createMessagePanel(g *gocui.Gui, currentView *gocui.View, title, prompt string) error {
2019-02-16 03:03:22 +02:00
return gui.createPopupPanel(g, currentView, title, prompt, false, nil, nil)
2018-05-27 08:32:09 +02:00
}
2018-06-01 15:23:31 +02:00
// createSpecificErrorPanel allows you to create an error popup, specifying the
// view to be focused when the user closes the popup, and a boolean specifying
// whether we will log the error. If the message may include a user password,
// this function is to be used over the more generic createErrorPanel, with
// willLog set to false
func (gui *Gui) createSpecificErrorPanel(message string, nextView *gocui.View, willLog bool) error {
if willLog {
go func() {
// when reporting is switched on this log call sometimes introduces
// a delay on the error panel popping up. Here I'm adding a second wait
// so that the error is logged while the user is reading the error message
time.Sleep(time.Second)
gui.Log.Error(message)
}()
}
2018-08-05 14:00:02 +02:00
colorFunction := color.New(color.FgRed).SprintFunc()
coloredMessage := colorFunction(strings.TrimSpace(message))
return gui.createConfirmationPanel(gui.g, nextView, gui.Tr.SLocalize("Error"), coloredMessage, nil, nil)
}
func (gui *Gui) createErrorPanel(g *gocui.Gui, message string) error {
return gui.createSpecificErrorPanel(message, g.CurrentView(), true)
2018-06-01 15:23:31 +02:00
}