mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-07 13:42:01 +02:00
add tooltip view for showing menu item descriptions
This commit is contained in:
parent
517e9445df
commit
f257740ea7
@ -91,8 +91,7 @@ func (gui *Gui) getConfirmationPanelDimensions(wrap bool, prompt string) (int, i
|
||||
return gui.getConfirmationPanelDimensionsAux(panelWidth, panelHeight)
|
||||
}
|
||||
|
||||
func (gui *Gui) getConfirmationPanelDimensionsForContentHeight(contentHeight int) (int, int, int, int) {
|
||||
panelWidth := gui.getConfirmationPanelWidth()
|
||||
func (gui *Gui) getConfirmationPanelDimensionsForContentHeight(panelWidth, contentHeight int) (int, int, int, int) {
|
||||
return gui.getConfirmationPanelDimensionsAux(panelWidth, contentHeight)
|
||||
}
|
||||
|
||||
|
@ -19,15 +19,18 @@ var _ types.IListContext = (*MenuContext)(nil)
|
||||
func NewMenuContext(
|
||||
view *gocui.View,
|
||||
|
||||
onFocus func(...types.OnFocusOpts) error,
|
||||
onRenderToMain func(...types.OnFocusOpts) error,
|
||||
onFocusLost func() error,
|
||||
|
||||
c *types.HelperCommon,
|
||||
getOptionsMap func() map[string]string,
|
||||
renderToDescriptionView func(string),
|
||||
) *MenuContext {
|
||||
viewModel := NewMenuViewModel()
|
||||
|
||||
onFocus := func(...types.OnFocusOpts) error {
|
||||
selectedMenuItem := viewModel.GetSelected()
|
||||
renderToDescriptionView(selectedMenuItem.Tooltip)
|
||||
return nil
|
||||
}
|
||||
|
||||
return &MenuContext{
|
||||
MenuViewModel: viewModel,
|
||||
ListContextTrait: &ListContextTrait{
|
||||
@ -38,9 +41,7 @@ func NewMenuContext(
|
||||
OnGetOptionsMap: getOptionsMap,
|
||||
Focusable: true,
|
||||
}), ContextCallbackOpts{
|
||||
OnFocus: onFocus,
|
||||
OnFocusLost: onFocusLost,
|
||||
OnRenderToMain: onRenderToMain,
|
||||
OnFocus: onFocus,
|
||||
}),
|
||||
getDisplayStrings: viewModel.GetDisplayStrings,
|
||||
list: viewModel,
|
||||
|
@ -55,11 +55,13 @@ func (self *UndoController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
||||
Key: opts.GetKey(opts.Config.Universal.Undo),
|
||||
Handler: self.reflogUndo,
|
||||
Description: self.c.Tr.LcUndoReflog,
|
||||
Tooltip: self.c.Tr.UndoTooltip,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Redo),
|
||||
Handler: self.reflogRedo,
|
||||
Description: self.c.Tr.LcRedoReflog,
|
||||
Tooltip: self.c.Tr.RedoTooltip,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,8 @@ func (self *FilesController) createResetMenu() error {
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||
},
|
||||
Key: 'D',
|
||||
Key: 'D',
|
||||
Tooltip: self.c.Tr.NukeDescription,
|
||||
},
|
||||
{
|
||||
DisplayStrings: []string{
|
||||
|
@ -365,25 +365,6 @@ func (gui *Gui) syncViewContexts() {
|
||||
}
|
||||
}
|
||||
|
||||
func initialViewContextMapping(contextTree *context.ContextTree) map[string]types.Context {
|
||||
return map[string]types.Context{
|
||||
"status": contextTree.Status,
|
||||
"files": contextTree.Files,
|
||||
"branches": contextTree.Branches,
|
||||
"remoteBranches": contextTree.RemoteBranches,
|
||||
"commits": contextTree.LocalCommits,
|
||||
"commitFiles": contextTree.CommitFiles,
|
||||
"subCommits": contextTree.SubCommits,
|
||||
"stash": contextTree.Stash,
|
||||
"menu": contextTree.Menu,
|
||||
"confirmation": contextTree.Confirmation,
|
||||
"commitMessage": contextTree.CommitMessage,
|
||||
"main": contextTree.Normal,
|
||||
"secondary": contextTree.Normal,
|
||||
"extras": contextTree.CommandLog,
|
||||
}
|
||||
}
|
||||
|
||||
// for now the split view will always be on
|
||||
// NewGui builds a new gui handler
|
||||
func NewGui(
|
||||
|
@ -88,6 +88,8 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
minimumWidth := 10
|
||||
gui.Views.Limit.Visible = height < minimumHeight || width < minimumWidth
|
||||
|
||||
gui.Views.Tooltip.Visible = gui.Views.Menu.Visible && gui.Views.Tooltip.Buffer() != ""
|
||||
|
||||
for _, context := range gui.TransientContexts() {
|
||||
view, err := gui.g.View(context.GetViewName())
|
||||
if err != nil && err.Error() != UNKNOWN_VIEW_ERROR_MSG {
|
||||
|
@ -15,11 +15,11 @@ import (
|
||||
func (gui *Gui) menuListContext() *context.MenuContext {
|
||||
return context.NewMenuContext(
|
||||
gui.Views.Menu,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
gui.c,
|
||||
gui.getMenuOptions,
|
||||
func(content string) {
|
||||
gui.Views.Tooltip.SetContent(content)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -36,16 +36,18 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
|
||||
}
|
||||
}
|
||||
|
||||
x0, y0, x1, y1 := gui.getConfirmationPanelDimensionsForContentHeight(len(opts.Items))
|
||||
menuView, _ := gui.g.SetView("menu", x0, y0, x1, y1, 0)
|
||||
menuView.Title = opts.Title
|
||||
menuView.FgColor = theme.GocuiDefaultTextColor
|
||||
menuView.SetOnSelectItem(gui.onSelectItemWrapper(func(selectedLine int) error {
|
||||
gui.State.Contexts.Menu.SetMenuItems(opts.Items)
|
||||
gui.State.Contexts.Menu.SetSelectedLineIdx(0)
|
||||
|
||||
gui.Views.Menu.Title = opts.Title
|
||||
gui.Views.Menu.FgColor = theme.GocuiDefaultTextColor
|
||||
gui.Views.Menu.SetOnSelectItem(gui.onSelectItemWrapper(func(selectedLine int) error {
|
||||
return nil
|
||||
}))
|
||||
|
||||
gui.State.Contexts.Menu.SetMenuItems(opts.Items)
|
||||
gui.State.Contexts.Menu.SetSelectedLineIdx(0)
|
||||
gui.Views.Tooltip.Wrap = true
|
||||
gui.Views.Tooltip.FgColor = theme.GocuiDefaultTextColor
|
||||
gui.Views.Tooltip.Visible = true
|
||||
|
||||
// resetting keybindings so that the menu-specific keybindings are registered
|
||||
if err := gui.resetKeybindings(); err != nil {
|
||||
@ -57,3 +59,16 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
|
||||
// TODO: ensure that if we're opened a menu from within a menu that it renders correctly
|
||||
return gui.c.PushContext(gui.State.Contexts.Menu)
|
||||
}
|
||||
|
||||
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("menu", 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("tooltip", x0, tooltipTop, x1, tooltipTop+tooltipHeight-1, 0)
|
||||
}
|
||||
|
@ -73,7 +73,8 @@ func (gui *Gui) handleCreateOptionsMenu() error {
|
||||
|
||||
return binding.Handler()
|
||||
},
|
||||
Key: binding.Key,
|
||||
Key: binding.Key,
|
||||
Tooltip: binding.Tooltip,
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -118,6 +118,9 @@ type MenuItem struct {
|
||||
// if Key is defined it allows the user to press the key to invoke the menu
|
||||
// item, as opposed to having to navigate to it
|
||||
Key Key
|
||||
|
||||
// the tooltip will be displayed upon highlighting the menu item
|
||||
Tooltip string
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
|
@ -17,6 +17,9 @@ type Binding struct {
|
||||
Alternative string
|
||||
Tag string // e.g. 'navigation'. Used for grouping things in the cheatsheet
|
||||
OpensMenu bool
|
||||
|
||||
// to be displayed if the keybinding is highlighted from within a menu
|
||||
Tooltip string
|
||||
}
|
||||
|
||||
// A guard is a decorator which checks something before executing a handler
|
||||
|
@ -47,9 +47,13 @@ func (gui *Gui) resizeCurrentPopupPanel() error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
if gui.isPopupPanel(v.Name()) {
|
||||
|
||||
if v == gui.Views.Menu {
|
||||
gui.resizeMenu()
|
||||
} else if gui.isPopupPanel(v.Name()) {
|
||||
return gui.resizePopupPanel(v, v.Buffer())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ package gui
|
||||
import (
|
||||
"github.com/jesseduffield/generics/slices"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
)
|
||||
|
||||
@ -27,7 +29,7 @@ type Views struct {
|
||||
SearchPrefix *gocui.View
|
||||
Limit *gocui.View
|
||||
Suggestions *gocui.View
|
||||
Description *gocui.View
|
||||
Tooltip *gocui.View
|
||||
Extras *gocui.View
|
||||
}
|
||||
|
||||
@ -71,7 +73,7 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping {
|
||||
{viewPtr: &gui.Views.Menu, name: "menu"},
|
||||
{viewPtr: &gui.Views.Suggestions, name: "suggestions"},
|
||||
{viewPtr: &gui.Views.Confirmation, name: "confirmation"},
|
||||
{viewPtr: &gui.Views.Description, name: "description"},
|
||||
{viewPtr: &gui.Views.Tooltip, name: "tooltip"},
|
||||
|
||||
// this guy will cover everything else when it appears
|
||||
{viewPtr: &gui.Views.Limit, name: "limit"},
|
||||
@ -105,7 +107,6 @@ func (gui *Gui) controlledViews() []controlledView {
|
||||
{viewName: "appStatus", windowName: "appStatus", frame: false},
|
||||
{viewName: "information", windowName: "information", frame: false},
|
||||
{viewName: "extras", windowName: "extras", frame: true},
|
||||
{viewName: "description", windowName: "description", frame: true},
|
||||
{viewName: "limit", windowName: "limit", frame: true},
|
||||
}
|
||||
}
|
||||
@ -180,10 +181,12 @@ func (gui *Gui) createAllViews() error {
|
||||
|
||||
gui.Views.Suggestions.Visible = false
|
||||
|
||||
gui.Views.Description.FgColor = theme.GocuiDefaultTextColor
|
||||
gui.Views.Tooltip.FgColor = theme.GocuiDefaultTextColor
|
||||
|
||||
gui.Views.Menu.Visible = false
|
||||
|
||||
gui.Views.Tooltip.Visible = false
|
||||
|
||||
gui.Views.Information.BgColor = gocui.ColorDefault
|
||||
gui.Views.Information.FgColor = gocui.ColorGreen
|
||||
|
||||
@ -194,3 +197,22 @@ func (gui *Gui) createAllViews() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initialViewContextMapping(contextTree *context.ContextTree) map[string]types.Context {
|
||||
return map[string]types.Context{
|
||||
"status": contextTree.Status,
|
||||
"files": contextTree.Files,
|
||||
"branches": contextTree.Branches,
|
||||
"remoteBranches": contextTree.RemoteBranches,
|
||||
"commits": contextTree.LocalCommits,
|
||||
"commitFiles": contextTree.CommitFiles,
|
||||
"subCommits": contextTree.SubCommits,
|
||||
"stash": contextTree.Stash,
|
||||
"menu": contextTree.Menu,
|
||||
"confirmation": contextTree.Confirmation,
|
||||
"commitMessage": contextTree.CommitMessage,
|
||||
"main": contextTree.Normal,
|
||||
"secondary": contextTree.Normal,
|
||||
"extras": contextTree.CommandLog,
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,8 @@ type TranslationSet struct {
|
||||
LcUndo string
|
||||
LcUndoReflog string
|
||||
LcRedoReflog string
|
||||
UndoTooltip string
|
||||
RedoTooltip string
|
||||
LcPop string
|
||||
LcDrop string
|
||||
LcApply string
|
||||
@ -486,6 +488,7 @@ type TranslationSet struct {
|
||||
CheckoutPrompt string
|
||||
HardResetAutostashPrompt string
|
||||
UpstreamGone string
|
||||
NukeDescription string
|
||||
Actions Actions
|
||||
Bisect Bisect
|
||||
}
|
||||
@ -719,6 +722,8 @@ func EnglishTranslationSet() TranslationSet {
|
||||
LcUndo: "undo",
|
||||
LcUndoReflog: "undo (via reflog) (experimental)",
|
||||
LcRedoReflog: "redo (via reflog) (experimental)",
|
||||
UndoTooltip: "The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration.",
|
||||
RedoTooltip: "The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration.",
|
||||
LcPop: "pop",
|
||||
LcDrop: "drop",
|
||||
LcApply: "apply",
|
||||
@ -1098,6 +1103,7 @@ func EnglishTranslationSet() TranslationSet {
|
||||
HardResetAutostashPrompt: "Are you sure you want to hard reset to '%s'? An auto-stash will be performed if necessary.",
|
||||
CheckoutPrompt: "Are you sure you want to checkout '%s'?",
|
||||
UpstreamGone: "(upstream gone)",
|
||||
NukeDescription: "If you want to make all the changes in the worktree go away, this is the way to do it. If there are dirty submodule changes this will stash those changes in the submodule(s).",
|
||||
Actions: Actions{
|
||||
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
||||
CheckoutCommit: "Checkout commit",
|
||||
|
Loading…
x
Reference in New Issue
Block a user