mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-23 00:39:13 +02:00
Merge branch 'feature/multiline-commit-restoring'
This commit is contained in:
1
ZHgalGrWSF
Normal file
1
ZHgalGrWSF
Normal file
@ -0,0 +1 @@
|
||||
GaUMygWjJa
|
43
commit_message_panel.go
Normal file
43
commit_message_panel.go
Normal file
@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import "github.com/jesseduffield/gocui"
|
||||
|
||||
func handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
|
||||
message := trimmedContent(v)
|
||||
if message == "" {
|
||||
return createErrorPanel(g, "You cannot commit without a commit message")
|
||||
}
|
||||
if output, err := gitCommit(g, message); err != nil {
|
||||
if err == errNoUsername {
|
||||
return createErrorPanel(g, err.Error())
|
||||
}
|
||||
return createErrorPanel(g, output)
|
||||
}
|
||||
refreshFiles(g)
|
||||
g.SetViewOnBottom("commitMessage")
|
||||
switchFocus(g, v, getFilesView(g))
|
||||
return refreshCommits(g)
|
||||
}
|
||||
|
||||
func handleCommitClose(g *gocui.Gui, v *gocui.View) error {
|
||||
g.SetViewOnBottom("commitMessage")
|
||||
return switchFocus(g, v, getFilesView(g))
|
||||
}
|
||||
|
||||
func handleNewlineCommitMessage(g *gocui.Gui, v *gocui.View) error {
|
||||
// resising ahead of time so that the top line doesn't get hidden to make
|
||||
// room for the cursor on the second line
|
||||
x0, y0, x1, y1 := getConfirmationPanelDimensions(g, v.Buffer())
|
||||
if _, err := g.SetView("commitMessage", x0, y0, x1, y1+1, 0); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
v.EditNewLine()
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleCommitFocused(g *gocui.Gui, v *gocui.View) error {
|
||||
return renderString(g, "options", "esc: close, enter: confirm")
|
||||
}
|
@ -56,6 +56,10 @@ func getConfirmationPanelDimensions(g *gocui.Gui, prompt string) (int, int, int,
|
||||
}
|
||||
|
||||
func createPromptPanel(g *gocui.Gui, currentView *gocui.View, title string, initialValue *[]byte, handleConfirm func(*gocui.Gui, *gocui.View) error) error {
|
||||
g.SetViewOnBottom("commitMessage")
|
||||
if initialValue == nil {
|
||||
initialValue = &[]byte{}
|
||||
}
|
||||
// only need to fit one line
|
||||
x0, y0, x1, y1 := getConfirmationPanelDimensions(g, "")
|
||||
if confirmationView, err := g.SetView("confirmation", x0, y0, x1, y1, 0); err != nil {
|
||||
@ -63,9 +67,7 @@ func createPromptPanel(g *gocui.Gui, currentView *gocui.View, title string, init
|
||||
return err
|
||||
}
|
||||
|
||||
g.Cursor = true
|
||||
|
||||
handleConfirmAndClear := func(gui *gocui.Gui, view *gocui.View) error {
|
||||
handleConfirm := func(gui *gocui.Gui, view *gocui.View) error {
|
||||
*initialValue = nil
|
||||
return handleConfirm(g, view)
|
||||
}
|
||||
@ -79,15 +81,31 @@ func createPromptPanel(g *gocui.Gui, currentView *gocui.View, title string, init
|
||||
|
||||
confirmationView.Editable = true
|
||||
confirmationView.Title = title
|
||||
confirmationView.Write(*initialValue)
|
||||
confirmationView.SetCursor(len(*initialValue), 0)
|
||||
restorePreviousBuffer(confirmationView, initialValue)
|
||||
switchFocus(g, currentView, confirmationView)
|
||||
return setKeyBindings(g, handleConfirmAndClear, handleClose)
|
||||
return setKeyBindings(g, handleConfirm, handleClose)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func restorePreviousBuffer(confirmationView *gocui.View, initialValue *[]byte) {
|
||||
confirmationView.Write(*initialValue)
|
||||
x, y := getCursorPositionFromBuffer(initialValue)
|
||||
devLog("New cursor position:", x, y)
|
||||
confirmationView.SetCursor(0, 0)
|
||||
confirmationView.MoveCursor(x, y, false)
|
||||
}
|
||||
|
||||
func getCursorPositionFromBuffer(initialValue *[]byte) (int, int) {
|
||||
split := strings.Split(string(*initialValue), "\n")
|
||||
lastLine := split[len(split)-1]
|
||||
x := len(lastLine)
|
||||
y := len(split)
|
||||
return x, y
|
||||
}
|
||||
|
||||
func createConfirmationPanel(g *gocui.Gui, currentView *gocui.View, title, prompt string, handleConfirm, handleClose func(*gocui.Gui, *gocui.View) error) error {
|
||||
g.SetViewOnBottom("commitMessage")
|
||||
g.Update(func(g *gocui.Gui) error {
|
||||
// delete the existing confirmation panel if it exists
|
||||
if view, _ := g.View("confirmation"); view != nil {
|
||||
@ -154,15 +172,20 @@ func trimTrailingNewline(str string) string {
|
||||
return str
|
||||
}
|
||||
|
||||
func resizeConfirmationPanel(g *gocui.Gui) error {
|
||||
func resizeConfirmationPanel(g *gocui.Gui, viewName string) error {
|
||||
// If the confirmation panel is already displayed, just resize the width,
|
||||
// otherwise continue
|
||||
if v, err := g.View("confirmation"); err == nil {
|
||||
content := trimTrailingNewline(v.Buffer())
|
||||
x0, y0, x1, y1 := getConfirmationPanelDimensions(g, content)
|
||||
if _, err = g.SetView("confirmation", x0, y0, x1, y1, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
g.Update(func(g *gocui.Gui) error {
|
||||
v, err := g.View(viewName)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
content := trimTrailingNewline(v.Buffer())
|
||||
x0, y0, x1, y1 := getConfirmationPanelDimensions(g, content)
|
||||
if _, err := g.SetView(viewName, x0, y0, x1, y1, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
savedCommitMessage = &[]byte{}
|
||||
errNoFiles = errors.New("No changed files")
|
||||
errNoUsername = errors.New(`No username set. Please do: git config --global user.name "Your Name"`)
|
||||
)
|
||||
@ -178,19 +177,11 @@ func handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
|
||||
if len(stagedFiles(state.GitFiles)) == 0 && !state.HasMergeConflicts {
|
||||
return createErrorPanel(g, "There are no staged files to commit")
|
||||
}
|
||||
createPromptPanel(g, filesView, "Commit message", savedCommitMessage, func(g *gocui.Gui, v *gocui.View) error {
|
||||
message := trimmedContent(v)
|
||||
if message == "" {
|
||||
return createErrorPanel(g, "You cannot commit without a commit message")
|
||||
}
|
||||
if output, err := gitCommit(g, message); err != nil {
|
||||
if err == errNoUsername {
|
||||
return createErrorPanel(g, err.Error())
|
||||
}
|
||||
return createErrorPanel(g, output)
|
||||
}
|
||||
refreshFiles(g)
|
||||
return refreshCommits(g)
|
||||
commitMessageView := getCommitMessageView(g)
|
||||
g.Update(func(g *gocui.Gui) error {
|
||||
g.SetViewOnTop("commitMessage")
|
||||
switchFocus(g, filesView, commitMessageView)
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
@ -107,13 +107,11 @@ func mergeGitStatusFiles(oldGitFiles, newGitFiles []GitFile) []GitFile {
|
||||
}
|
||||
|
||||
func runDirectCommand(command string) (string, error) {
|
||||
timeStart := time.Now()
|
||||
commandLog(command)
|
||||
|
||||
cmdOut, err := exec.
|
||||
Command(state.Platform.shell, state.Platform.shellArg, command).
|
||||
CombinedOutput()
|
||||
devLog("run direct command time for command: ", command, time.Now().Sub(timeStart))
|
||||
return sanitisedCommandOutput(cmdOut, err)
|
||||
}
|
||||
|
||||
@ -218,12 +216,9 @@ func sanitisedCommandOutput(output []byte, err error) (string, error) {
|
||||
}
|
||||
|
||||
func runCommand(command string) (string, error) {
|
||||
commandStartTime := time.Now()
|
||||
commandLog(command)
|
||||
splitCmd := strings.Split(command, " ")
|
||||
devLog(splitCmd)
|
||||
cmdOut, err := exec.Command(splitCmd[0], splitCmd[1:]...).CombinedOutput()
|
||||
devLog("run command time: ", time.Now().Sub(commandStartTime))
|
||||
return sanitisedCommandOutput(cmdOut, err)
|
||||
}
|
||||
|
||||
|
15
gui.go
15
gui.go
@ -199,14 +199,25 @@ func layout(g *gocui.Gui) error {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
v.BgColor = gocui.ColorDefault
|
||||
v.FgColor = gocui.ColorBlue
|
||||
v.Frame = false
|
||||
}
|
||||
|
||||
if err = resizeConfirmationPanel(g); err != nil {
|
||||
if getCommitMessageView(g) == nil {
|
||||
// doesn't matter where this view starts because it will be hidden
|
||||
if commitMessageView, err := g.SetView("commitMessage", 0, 0, width, height, 0); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
g.SetViewOnBottom("commitMessage")
|
||||
commitMessageView.Title = "Commit message"
|
||||
commitMessageView.FgColor = gocui.ColorWhite
|
||||
commitMessageView.Editable = true
|
||||
}
|
||||
}
|
||||
|
||||
resizeConfirmationPanel(g, "commitMessage")
|
||||
resizeConfirmationPanel(g, "confirmation")
|
||||
|
||||
if v, err := g.SetView("version", width-len(version)-1, optionsTop, width, optionsTop+2, 0); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
|
@ -58,6 +58,9 @@ func keybindings(g *gocui.Gui) error {
|
||||
{ViewName: "stash", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handleStashApply},
|
||||
{ViewName: "stash", Key: 'g', Modifier: gocui.ModNone, Handler: handleStashPop},
|
||||
{ViewName: "stash", Key: 'd', Modifier: gocui.ModNone, Handler: handleStashDrop},
|
||||
{ViewName: "commitMessage", Key: gocui.KeyEnter, Modifier: gocui.ModNone, Handler: handleCommitConfirm},
|
||||
{ViewName: "commitMessage", Key: gocui.KeyEsc, Modifier: gocui.ModNone, Handler: handleCommitClose},
|
||||
{ViewName: "commitMessage", Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: handleNewlineCommitMessage},
|
||||
}
|
||||
|
||||
// Would make these keybindings global but that interferes with editing
|
||||
|
@ -75,6 +75,8 @@ func newLineFocused(g *gocui.Gui, v *gocui.View) error {
|
||||
return handleBranchSelect(g, v)
|
||||
case "confirmation":
|
||||
return nil
|
||||
case "commitMessage":
|
||||
return handleCommitFocused(g, v)
|
||||
case "main":
|
||||
// TODO: pull this out into a 'view focused' function
|
||||
refreshMergePanel(g)
|
||||
@ -215,3 +217,19 @@ func loader() string {
|
||||
index := nanos / 50000000 % int64(len(characters))
|
||||
return characters[index : index+1]
|
||||
}
|
||||
|
||||
// TODO: refactor properly
|
||||
func getFilesView(g *gocui.Gui) *gocui.View {
|
||||
v, _ := g.View("files")
|
||||
return v
|
||||
}
|
||||
|
||||
func getCommitsView(g *gocui.Gui) *gocui.View {
|
||||
v, _ := g.View("commits")
|
||||
return v
|
||||
}
|
||||
|
||||
func getCommitMessageView(g *gocui.Gui) *gocui.View {
|
||||
v, _ := g.View("commitMessage")
|
||||
return v
|
||||
}
|
||||
|
Reference in New Issue
Block a user