mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-08-09 09:22:48 +03:00
standardise rendering of lists in panels
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/git"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error {
|
||||
@@ -109,7 +110,7 @@ func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectedBranch(v *gocui.View) commands.Branch {
|
||||
func (gui *Gui) getSelectedBranch(v *gocui.View) *commands.Branch {
|
||||
lineNumber := gui.getItemPosition(v)
|
||||
return gui.State.Branches[lineNumber]
|
||||
}
|
||||
@@ -151,12 +152,15 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error {
|
||||
return err
|
||||
}
|
||||
gui.State.Branches = builder.Build()
|
||||
|
||||
v.Clear()
|
||||
displayStrings := make([]string, len(gui.State.Branches))
|
||||
for i, branch := range gui.State.Branches {
|
||||
displayStrings[i] = branch.GetDisplayString()
|
||||
list, err := utils.RenderList(gui.State.Branches)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(v, strings.Join(displayStrings, "\n"))
|
||||
|
||||
fmt.Fprint(v, list)
|
||||
|
||||
gui.resetOrigin(v)
|
||||
return gui.refreshStatus(g)
|
||||
})
|
||||
|
@@ -3,26 +3,12 @@ package gui
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
func (gui *Gui) renderCommit(commit commands.Commit) string {
|
||||
red := color.New(color.FgRed)
|
||||
yellow := color.New(color.FgYellow)
|
||||
white := color.New(color.FgWhite)
|
||||
|
||||
shaColor := yellow
|
||||
if commit.Pushed {
|
||||
shaColor = red
|
||||
}
|
||||
|
||||
return shaColor.Sprint(commit.Sha) + " " + white.Sprint(commit.Name)
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshCommits(g *gocui.Gui) error {
|
||||
g.Update(func(*gocui.Gui) error {
|
||||
gui.State.Commits = gui.GitCommand.GetCommits()
|
||||
@@ -30,12 +16,14 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Clear()
|
||||
displayStrings := make([]string, len(gui.State.Commits))
|
||||
for i, commit := range gui.State.Commits {
|
||||
displayStrings[i] = gui.renderCommit(commit)
|
||||
list, err := utils.RenderList(gui.State.Commits)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(v, strings.Join(displayStrings, "\n"))
|
||||
fmt.Fprint(v, list)
|
||||
|
||||
gui.refreshStatus(g)
|
||||
if g.CurrentView().Name() == "commits" {
|
||||
gui.handleCommitSelect(g, v)
|
||||
@@ -106,7 +94,7 @@ func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
|
||||
}
|
||||
|
||||
// TODO: move to files panel
|
||||
func (gui *Gui) anyUnStagedChanges(files []commands.File) bool {
|
||||
func (gui *Gui) anyUnStagedChanges(files []*commands.File) bool {
|
||||
for _, file := range files {
|
||||
if file.Tracked && file.HasUnstagedChanges {
|
||||
return true
|
||||
@@ -169,13 +157,13 @@ func (gui *Gui) handleRenameCommitEditor(g *gocui.Gui, v *gocui.View) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectedCommit(g *gocui.Gui) (commands.Commit, error) {
|
||||
func (gui *Gui) getSelectedCommit(g *gocui.Gui) (*commands.Commit, error) {
|
||||
v, err := g.View("commits")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(gui.State.Commits) == 0 {
|
||||
return commands.Commit{}, errors.New(gui.Tr.SLocalize("NoCommitsThisBranch"))
|
||||
return &commands.Commit{}, errors.New(gui.Tr.SLocalize("NoCommitsThisBranch"))
|
||||
}
|
||||
lineNumber := gui.getItemPosition(v)
|
||||
if lineNumber > len(gui.State.Commits)-1 {
|
||||
|
@@ -10,14 +10,14 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
func (gui *Gui) stagedFiles() []commands.File {
|
||||
func (gui *Gui) stagedFiles() []*commands.File {
|
||||
files := gui.State.Files
|
||||
result := make([]commands.File, 0)
|
||||
result := make([]*commands.File, 0)
|
||||
for _, file := range files {
|
||||
if file.HasStagedChanges {
|
||||
result = append(result, file)
|
||||
@@ -26,9 +26,9 @@ func (gui *Gui) stagedFiles() []commands.File {
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) trackedFiles() []commands.File {
|
||||
func (gui *Gui) trackedFiles() []*commands.File {
|
||||
files := gui.State.Files
|
||||
result := make([]commands.File, 0)
|
||||
result := make([]*commands.File, 0)
|
||||
for _, file := range files {
|
||||
if file.Tracked {
|
||||
result = append(result, file)
|
||||
@@ -117,9 +117,9 @@ func (gui *Gui) handleAddPatch(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.Errors.ErrSubProcess
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectedFile(g *gocui.Gui) (commands.File, error) {
|
||||
func (gui *Gui) getSelectedFile(g *gocui.Gui) (*commands.File, error) {
|
||||
if len(gui.State.Files) == 0 {
|
||||
return commands.File{}, gui.Errors.ErrNoFiles
|
||||
return &commands.File{}, gui.Errors.ErrNoFiles
|
||||
}
|
||||
filesView, err := g.View("files")
|
||||
if err != nil {
|
||||
@@ -185,7 +185,7 @@ func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View) error {
|
||||
gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedFiles"))
|
||||
return gui.renderfilesOptions(g, nil)
|
||||
}
|
||||
gui.renderfilesOptions(g, &file)
|
||||
gui.renderfilesOptions(g, file)
|
||||
var content string
|
||||
if file.HasMergeConflicts {
|
||||
return gui.refreshMergePanel(g)
|
||||
@@ -276,25 +276,6 @@ func (gui *Gui) updateHasMergeConflictStatus() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) renderFile(file commands.File) string {
|
||||
// potentially inefficient to be instantiating these color
|
||||
// objects with each render
|
||||
red := color.New(color.FgRed)
|
||||
green := color.New(color.FgGreen)
|
||||
if !file.Tracked && !file.HasStagedChanges {
|
||||
return red.Sprint(file.DisplayString)
|
||||
}
|
||||
|
||||
output := green.Sprint(file.DisplayString[0:1])
|
||||
output += red.Sprint(file.DisplayString[1:3])
|
||||
if file.HasUnstagedChanges {
|
||||
output += red.Sprint(file.Name)
|
||||
} else {
|
||||
output += green.Sprint(file.Name)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) {
|
||||
item, err := gui.getSelectedFile(g)
|
||||
if err != nil {
|
||||
@@ -321,13 +302,12 @@ func (gui *Gui) refreshFiles(g *gocui.Gui) error {
|
||||
}
|
||||
gui.refreshStateFiles()
|
||||
|
||||
displayStrings := make([]string, len(gui.State.Files))
|
||||
for i, file := range gui.State.Files {
|
||||
displayStrings[i] = gui.renderFile(file)
|
||||
}
|
||||
|
||||
filesView.Clear()
|
||||
fmt.Fprint(filesView, strings.Join(displayStrings, "\n"))
|
||||
list, err := utils.RenderList(gui.State.Files)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(filesView, list)
|
||||
|
||||
gui.correctCursor(filesView)
|
||||
if filesView == g.CurrentView() {
|
||||
|
@@ -71,10 +71,10 @@ type Gui struct {
|
||||
}
|
||||
|
||||
type guiState struct {
|
||||
Files []commands.File
|
||||
Branches []commands.Branch
|
||||
Commits []commands.Commit
|
||||
StashEntries []commands.StashEntry
|
||||
Files []*commands.File
|
||||
Branches []*commands.Branch
|
||||
Commits []*commands.Commit
|
||||
StashEntries []*commands.StashEntry
|
||||
PreviousView string
|
||||
HasMergeConflicts bool
|
||||
ConflictIndex int
|
||||
@@ -83,17 +83,17 @@ type guiState struct {
|
||||
EditHistory *stack.Stack
|
||||
Platform commands.Platform
|
||||
Updating bool
|
||||
Keys []Binding
|
||||
Keys []*Binding
|
||||
}
|
||||
|
||||
// NewGui builds a new gui handler
|
||||
func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *commands.OSCommand, tr *i18n.Localizer, config config.AppConfigurer, updater *updates.Updater) (*Gui, error) {
|
||||
|
||||
initialState := guiState{
|
||||
Files: make([]commands.File, 0),
|
||||
Files: make([]*commands.File, 0),
|
||||
PreviousView: "files",
|
||||
Commits: make([]commands.Commit, 0),
|
||||
StashEntries: make([]commands.StashEntry, 0),
|
||||
Commits: make([]*commands.Commit, 0),
|
||||
StashEntries: make([]*commands.StashEntry, 0),
|
||||
ConflictIndex: 0,
|
||||
ConflictTop: true,
|
||||
Conflicts: make([]commands.Conflict, 0),
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package gui
|
||||
|
||||
import "github.com/jesseduffield/gocui"
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
// Binding - a keybinding mapping a key and modifier to a handler. The keypress
|
||||
// is only handled if the given view has focus, or handled globally if the view
|
||||
@@ -14,8 +16,26 @@ type Binding struct {
|
||||
Description string
|
||||
}
|
||||
|
||||
func (gui *Gui) GetKeybindings() []Binding {
|
||||
bindings := []Binding{
|
||||
// GetDisplayStrings returns the display string of a file
|
||||
func (b *Binding) GetDisplayStrings() []string {
|
||||
return []string{b.GetKey(), b.Description}
|
||||
}
|
||||
|
||||
func (b *Binding) GetKey() string {
|
||||
r, ok := b.Key.(rune)
|
||||
key := ""
|
||||
|
||||
if ok {
|
||||
key = string(r)
|
||||
} else if b.KeyReadable != "" {
|
||||
key = b.KeyReadable
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
func (gui *Gui) GetKeybindings() []*Binding {
|
||||
bindings := []*Binding{
|
||||
{
|
||||
ViewName: "",
|
||||
Key: 'q',
|
||||
@@ -360,7 +380,7 @@ func (gui *Gui) GetKeybindings() []Binding {
|
||||
// Would make these keybindings global but that interferes with editing
|
||||
// input in the confirmation panel
|
||||
for _, viewName := range []string{"status", "files", "branches", "commits", "stash", "menu"} {
|
||||
bindings = append(bindings, []Binding{
|
||||
bindings = append(bindings, []*Binding{
|
||||
{ViewName: viewName, Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView},
|
||||
{ViewName: viewName, Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView},
|
||||
{ViewName: viewName, Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: gui.nextView},
|
||||
|
@@ -49,50 +49,20 @@ func (gui *Gui) handleMenuClose(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.returnFocus(g, v)
|
||||
}
|
||||
|
||||
func (gui *Gui) GetKey(binding Binding) string {
|
||||
r, ok := binding.Key.(rune)
|
||||
key := ""
|
||||
|
||||
if ok {
|
||||
key = string(r)
|
||||
} else if binding.KeyReadable != "" {
|
||||
key = binding.KeyReadable
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
func (gui *Gui) GetMaxKeyLength(bindings []Binding) int {
|
||||
max := 0
|
||||
for _, binding := range bindings {
|
||||
keyLength := len(gui.GetKey(binding))
|
||||
if keyLength > max {
|
||||
max = keyLength
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
func (gui *Gui) handleMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
var (
|
||||
contentGlobal, contentPanel []string
|
||||
bindingsGlobal, bindingsPanel []Binding
|
||||
bindingsGlobal, bindingsPanel []*Binding
|
||||
)
|
||||
// clear keys slice, so we don't have ghost elements
|
||||
gui.State.Keys = gui.State.Keys[:0]
|
||||
bindings := gui.GetKeybindings()
|
||||
padWidth := gui.GetMaxKeyLength(bindings)
|
||||
|
||||
for _, binding := range bindings {
|
||||
key := gui.GetKey(binding)
|
||||
if key != "" && binding.Description != "" {
|
||||
content := fmt.Sprintf("%s %s", utils.WithPadding(key, padWidth), binding.Description)
|
||||
if binding.GetKey() != "" && binding.Description != "" {
|
||||
switch binding.ViewName {
|
||||
case "":
|
||||
contentGlobal = append(contentGlobal, content)
|
||||
bindingsGlobal = append(bindingsGlobal, binding)
|
||||
case v.Name():
|
||||
contentPanel = append(contentPanel, content)
|
||||
bindingsPanel = append(bindingsPanel, binding)
|
||||
}
|
||||
}
|
||||
@@ -100,24 +70,25 @@ func (gui *Gui) handleMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
|
||||
// append dummy element to have a separator between
|
||||
// panel and global keybindings
|
||||
contentPanel = append(contentPanel, "")
|
||||
bindingsPanel = append(bindingsPanel, Binding{})
|
||||
|
||||
content := append(contentPanel, contentGlobal...)
|
||||
bindingsPanel = append(bindingsPanel, &Binding{})
|
||||
gui.State.Keys = append(bindingsPanel, bindingsGlobal...)
|
||||
contentJoined := strings.Join(content, "\n")
|
||||
|
||||
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(g, contentJoined)
|
||||
list, err := utils.RenderList(gui.State.Keys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(g, list)
|
||||
menuView, _ := g.SetView("menu", x0, y0, x1, y1, 0)
|
||||
menuView.Title = strings.Title(gui.Tr.SLocalize("menu"))
|
||||
menuView.FgColor = gocui.ColorWhite
|
||||
menuView.Clear()
|
||||
fmt.Fprint(menuView, list)
|
||||
|
||||
if err := gui.renderMenuOptions(g); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprint(menuView, contentJoined)
|
||||
|
||||
g.Update(func(g *gocui.Gui) error {
|
||||
_, err := g.SetViewOnTop("menu")
|
||||
if err != nil {
|
||||
|
@@ -2,10 +2,10 @@ package gui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
func (gui *Gui) refreshStashEntries(g *gocui.Gui) error {
|
||||
@@ -16,13 +16,12 @@ func (gui *Gui) refreshStashEntries(g *gocui.Gui) error {
|
||||
}
|
||||
gui.State.StashEntries = gui.GitCommand.GetStashEntries()
|
||||
|
||||
displayStrings := make([]string, len(gui.State.StashEntries))
|
||||
for i, stashEntry := range gui.State.StashEntries {
|
||||
displayStrings[i] = stashEntry.DisplayString
|
||||
}
|
||||
|
||||
v.Clear()
|
||||
fmt.Fprint(v, strings.Join(displayStrings, "\n"))
|
||||
list, err := utils.RenderList(gui.State.StashEntries)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(v, list)
|
||||
|
||||
return gui.resetOrigin(v)
|
||||
})
|
||||
@@ -35,7 +34,7 @@ func (gui *Gui) getSelectedStashEntry(v *gocui.View) *commands.StashEntry {
|
||||
}
|
||||
stashView, _ := gui.g.View("stash")
|
||||
lineNumber := gui.getItemPosition(stashView)
|
||||
return &gui.State.StashEntries[lineNumber]
|
||||
return gui.State.StashEntries[lineNumber]
|
||||
}
|
||||
|
||||
func (gui *Gui) renderStashOptions(g *gocui.Gui) error {
|
||||
|
Reference in New Issue
Block a user