From 1c99aaff4349d55bedb0bce9b4771933fb746b6b Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 5 Aug 2018 22:00:02 +1000 Subject: [PATCH] basic support for overlapping panels --- confirmation_panel.go | 163 ++++++++++++++++++++---------------------- gui.go | 58 +++++++++------ 2 files changed, 116 insertions(+), 105 deletions(-) diff --git a/confirmation_panel.go b/confirmation_panel.go index 1d05486ef..16f9ac0c9 100644 --- a/confirmation_panel.go +++ b/confirmation_panel.go @@ -7,118 +7,113 @@ package main import ( + "strings" - // "io" - // "io/ioutil" - - "strings" - // "strings" - - "github.com/fatih/color" - "github.com/jesseduffield/gocui" + "github.com/fatih/color" + "github.com/jesseduffield/gocui" ) func wrappedConfirmationFunction(function func(*gocui.Gui, *gocui.View) error) func(*gocui.Gui, *gocui.View) error { - return func(g *gocui.Gui, v *gocui.View) error { - if function != nil { - if err := function(g, v); err != nil { - panic(err) - } - } - return closeConfirmationPrompt(g) - } + return func(g *gocui.Gui, v *gocui.View) error { + if function != nil { + if err := function(g, v); err != nil { + panic(err) + } + } + return closeConfirmationPrompt(g) + } } func closeConfirmationPrompt(g *gocui.Gui) error { - view, err := g.View("confirmation") - if err != nil { - panic(err) - } - if err := returnFocus(g, view); err != nil { - panic(err) - } - g.DeleteKeybindings("confirmation") - return g.DeleteView("confirmation") + view, err := g.View("confirmation") + if err != nil { + panic(err) + } + if err := returnFocus(g, view); err != nil { + panic(err) + } + g.DeleteKeybindings("confirmation") + return g.DeleteView("confirmation") } func getMessageHeight(message string, width int) int { - lines := strings.Split(message, "\n") - lineCount := 0 - for _, line := range lines { - lineCount += len(line)/width + 1 - } - return lineCount + lines := strings.Split(message, "\n") + lineCount := 0 + for _, line := range lines { + lineCount += len(line)/width + 1 + } + return lineCount } func getConfirmationPanelDimensions(g *gocui.Gui, prompt string) (int, int, int, int) { - width, height := g.Size() - panelWidth := 60 - panelHeight := getMessageHeight(prompt, panelWidth) - return width/2 - panelWidth/2, - height/2 - panelHeight/2 - panelHeight%2 - 1, - width/2 + panelWidth/2, - height/2 + panelHeight/2 + width, height := g.Size() + panelWidth := 60 + panelHeight := getMessageHeight(prompt, panelWidth) + return width/2 - panelWidth/2, + height/2 - panelHeight/2 - panelHeight%2 - 1, + width/2 + panelWidth/2, + height/2 + panelHeight/2 } func createPromptPanel(g *gocui.Gui, currentView *gocui.View, title string, handleYes func(*gocui.Gui, *gocui.View) error) error { - // only need to fit one line - x0, y0, x1, y1 := getConfirmationPanelDimensions(g, "") - if confirmationView, err := g.SetView("confirmation", x0, y0, x1, y1); err != nil { - if err != gocui.ErrUnknownView { - return err - } + // 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 { + if err != gocui.ErrUnknownView { + return err + } - confirmationView.Editable = true - g.Cursor = true + confirmationView.Editable = true + g.Cursor = true - confirmationView.Title = title - switchFocus(g, currentView, confirmationView) - return setKeyBindings(g, handleYes, nil) - } - return nil + confirmationView.Title = title + switchFocus(g, currentView, confirmationView) + return setKeyBindings(g, handleYes, nil) + } + return nil } func createConfirmationPanel(g *gocui.Gui, currentView *gocui.View, title, prompt string, handleYes, handleNo func(*gocui.Gui, *gocui.View) error) error { - g.Update(func(g *gocui.Gui) error { - // delete the existing confirmation panel if it exists - if view, _ := g.View("confirmation"); view != nil { - if err := closeConfirmationPrompt(g); err != nil { - panic(err) - } - } - x0, y0, x1, y1 := getConfirmationPanelDimensions(g, prompt) - if confirmationView, err := g.SetView("confirmation", x0, y0, x1, y1); err != nil { - if err != gocui.ErrUnknownView { - return err - } - confirmationView.Title = title - renderString(g, "confirmation", prompt) - switchFocus(g, currentView, confirmationView) - return setKeyBindings(g, handleYes, handleNo) - } - return nil - }) - return nil + g.Update(func(g *gocui.Gui) error { + // delete the existing confirmation panel if it exists + if view, _ := g.View("confirmation"); view != nil { + if err := closeConfirmationPrompt(g); err != nil { + panic(err) + } + } + x0, y0, x1, y1 := getConfirmationPanelDimensions(g, prompt) + if confirmationView, err := g.SetView("confirmation", x0, y0, x1, y1, 0); err != nil { + if err != gocui.ErrUnknownView { + return err + } + confirmationView.Title = title + renderString(g, "confirmation", prompt) + switchFocus(g, currentView, confirmationView) + return setKeyBindings(g, handleYes, handleNo) + } + return nil + }) + return nil } func setKeyBindings(g *gocui.Gui, handleYes, handleNo func(*gocui.Gui, *gocui.View) error) error { - renderString(g, "options", "esc: close, enter: confirm") - if err := g.SetKeybinding("confirmation", gocui.KeyEnter, gocui.ModNone, wrappedConfirmationFunction(handleYes)); err != nil { - return err - } - if err := g.SetKeybinding("confirmation", gocui.KeyEsc, gocui.ModNone, wrappedConfirmationFunction(handleNo)); err != nil { - return err - } - return nil + renderString(g, "options", "esc: close, enter: confirm") + if err := g.SetKeybinding("confirmation", gocui.KeyEnter, gocui.ModNone, wrappedConfirmationFunction(handleYes)); err != nil { + return err + } + if err := g.SetKeybinding("confirmation", gocui.KeyEsc, gocui.ModNone, wrappedConfirmationFunction(handleNo)); err != nil { + return err + } + return nil } func createMessagePanel(g *gocui.Gui, currentView *gocui.View, title, prompt string) error { - return createConfirmationPanel(g, currentView, title, prompt, nil, nil) + return createConfirmationPanel(g, currentView, title, prompt, nil, nil) } func createErrorPanel(g *gocui.Gui, message string) error { - currentView := g.CurrentView() - colorFunction := color.New(color.FgRed).SprintFunc() - coloredMessage := colorFunction(strings.TrimSpace(message)) - return createConfirmationPanel(g, currentView, "Error", coloredMessage, nil, nil) + currentView := g.CurrentView() + colorFunction := color.New(color.FgRed).SprintFunc() + coloredMessage := colorFunction(strings.TrimSpace(message)) + return createConfirmationPanel(g, currentView, "Error", coloredMessage, nil, nil) } diff --git a/gui.go b/gui.go index 55aa81875..e55ba34fe 100644 --- a/gui.go +++ b/gui.go @@ -205,6 +205,22 @@ func layout(g *gocui.Gui) error { filesBranchesBoundary := 2 * height / 5 // height - 20 commitsBranchesBoundary := 3 * height / 5 // height - 10 commitsStashBoundary := height - 5 // height - 5 + panelSpacing := 1 + minimumHeight := 16 + + if height < minimumHeight { + v, err := g.SetView("limit", 0, 0, width-1, height-1, 0) + if err != nil { + if err != gocui.ErrUnknownView { + return err + } + v.Title = "Not enough space to render panels" + v.Wrap = true + } + return nil + } else { + g.DeleteView("limit") + } optionsTop := height - 2 // hiding options if there's not enough space @@ -212,7 +228,23 @@ func layout(g *gocui.Gui) error { optionsTop = height - 1 } - filesView, err := g.SetView("files", 0, statusFilesBoundary+1, leftSideWidth, filesBranchesBoundary-1) + v, err := g.SetView("main", leftSideWidth+panelSpacing, 0, width-1, optionsTop, gocui.LEFT) + if err != nil { + if err != gocui.ErrUnknownView { + return err + } + v.Title = "Diff" + v.Wrap = true + } + + if v, err := g.SetView("status", 0, 0, leftSideWidth, statusFilesBoundary, gocui.BOTTOM|gocui.RIGHT); err != nil { + if err != gocui.ErrUnknownView { + return err + } + v.Title = "Status" + } + + filesView, err := g.SetView("files", 0, statusFilesBoundary+panelSpacing, leftSideWidth, filesBranchesBoundary, gocui.TOP|gocui.BOTTOM) if err != nil { if err != gocui.ErrUnknownView { return err @@ -221,23 +253,7 @@ func layout(g *gocui.Gui) error { filesView.Title = "Files" } - if v, err := g.SetView("status", 0, statusFilesBoundary-2, leftSideWidth, statusFilesBoundary); err != nil { - if err != gocui.ErrUnknownView { - return err - } - v.Title = "Status" - } - - mainView, err := g.SetView("main", leftSideWidth+1, 0, width-1, optionsTop) - if err != nil { - if err != gocui.ErrUnknownView { - return err - } - mainView.Title = "Diff" - mainView.Wrap = true - } - - if v, err := g.SetView("branches", 0, filesBranchesBoundary, leftSideWidth, commitsBranchesBoundary-1); err != nil { + if v, err := g.SetView("branches", 0, filesBranchesBoundary+panelSpacing, leftSideWidth, commitsBranchesBoundary, gocui.TOP|gocui.BOTTOM); err != nil { if err != gocui.ErrUnknownView { return err } @@ -245,7 +261,7 @@ func layout(g *gocui.Gui) error { } - if v, err := g.SetView("commits", 0, commitsBranchesBoundary, leftSideWidth, commitsStashBoundary-1); err != nil { + if v, err := g.SetView("commits", 0, commitsBranchesBoundary+panelSpacing, leftSideWidth, commitsStashBoundary, gocui.TOP|gocui.BOTTOM); err != nil { if err != gocui.ErrUnknownView { return err } @@ -253,14 +269,14 @@ func layout(g *gocui.Gui) error { } - if v, err := g.SetView("stash", 0, commitsStashBoundary, leftSideWidth, optionsTop); err != nil { + if v, err := g.SetView("stash", 0, commitsStashBoundary+panelSpacing, leftSideWidth, optionsTop, gocui.TOP|gocui.RIGHT); err != nil { if err != gocui.ErrUnknownView { return err } v.Title = "Stash" } - if v, err := g.SetView("options", -1, optionsTop, width, optionsTop+2); err != nil { + if v, err := g.SetView("options", -1, optionsTop, width, optionsTop+2, 0); err != nil { if err != gocui.ErrUnknownView { return err }