diff options
author | dwillist <dthornton@vmware.com> | 2021-01-18 20:07:33 -0500 |
---|---|---|
committer | dwillist <dthornton@vmware.com> | 2021-01-18 20:07:33 -0500 |
commit | 9f745c7c8bd037e911c7c5aa6a78c509a98304d9 (patch) | |
tree | 9a405130f7892be3bef815978d14dae8fb55af4f | |
parent | cf5af7d5b52320e3b2e8083a08468e73d2a98b08 (diff) |
update styling and improve keybinding display
Signed-off-by: dwillist <dthornton@vmware.com>
-rw-r--r-- | cmd/root.go | 14 | ||||
-rw-r--r-- | runtime/ui/app.go | 7 | ||||
-rw-r--r-- | runtime/ui/components/filetree_primative.go | 28 | ||||
-rw-r--r-- | runtime/ui/components/key_config.go | 53 | ||||
-rw-r--r-- | runtime/ui/components/keybinding_primitive.go | 33 | ||||
-rw-r--r-- | runtime/ui/components/layers_primative.go | 68 | ||||
-rw-r--r-- | runtime/ui/components/wrapper_primative.go | 20 | ||||
-rw-r--r-- | runtime/ui/format/format.go | 27 |
8 files changed, 159 insertions, 91 deletions
diff --git a/cmd/root.go b/cmd/root.go index bdce3db..cc7a569 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -118,39 +118,39 @@ func initConfig() { tcell.NewEventKey(tcell.KeyCtrlSpace, rune(0), tcell.ModCtrl), )) viper.SetDefault("keybinding.toggle-filetree-attributes", components.NewKeyBinding( - "FileTree Attributes", + "Attributes", tcell.NewEventKey(tcell.KeyCtrlB, rune(0), tcell.ModCtrl), )) viper.SetDefault("keybinding.toggle-added-files", components.NewKeyBinding( - "Added Files", + "Added", tcell.NewEventKey(tcell.KeyCtrlA, rune(0), tcell.ModCtrl), )) viper.SetDefault("keybinding.toggle-removed-files", components.NewKeyBinding( - "Removed Files", + "Removed", tcell.NewEventKey(tcell.KeyCtrlR, rune(0), tcell.ModCtrl), )) viper.SetDefault("keybinding.toggle-modified-files", components.NewKeyBinding( - "Modified Files", + "Modified", tcell.NewEventKey(tcell.KeyCtrlM, rune(0), tcell.ModCtrl), )) viper.SetDefault("keybinding.toggle-unmodified-files", components.NewKeyBinding( - "Unmodified Files", + "Unmodified", tcell.NewEventKey(tcell.KeyCtrlU, rune(0), tcell.ModCtrl), )) viper.SetDefault("keybinding.page-up", components.NewKeyBinding( - "Page Up", + "Pg Up", tcell.NewEventKey(tcell.KeyPgUp, rune(0), tcell.ModNone), )) viper.SetDefault("keybinding.page-down", components.NewKeyBinding( - "Page Down", + "Pg Down", tcell.NewEventKey(tcell.KeyPgDn, rune(0), tcell.ModNone), )) diff --git a/runtime/ui/app.go b/runtime/ui/app.go index a7d013a..e9511f4 100644 --- a/runtime/ui/app.go +++ b/runtime/ui/app.go @@ -1,6 +1,7 @@ package ui import ( + "fmt" "os" "sync" @@ -72,11 +73,13 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr filterView := components.NewFilterView(treeViewModel).Setup() layersView := components.NewLayerList(treeViewModel).Setup(config) - layersBox := components.NewWrapper("Layers", "subtitle!", layersView).Setup() + + layerSubtitle := fmt.Sprintf("Cmp%7s %s", "Size", "Command") + layersBox := components.NewWrapper("Layers", layerSubtitle, layersView).Setup() fileTreeView := components.NewTreeView(treeViewModel) fileTreeView = fileTreeView.Setup(config) - fileTreeBox := components.NewWrapper("Current Layer Contents", "subtitle!", fileTreeView).Setup() + fileTreeBox := components.NewWrapper("Current Layer Contents", "", fileTreeView).Setup() keyMenuView := components.NewKeyMenuView() diff --git a/runtime/ui/components/filetree_primative.go b/runtime/ui/components/filetree_primative.go index 8cb41fe..1ce7027 100644 --- a/runtime/ui/components/filetree_primative.go +++ b/runtime/ui/components/filetree_primative.go @@ -207,13 +207,20 @@ func (t *TreeView) Setup(config KeyBindingConfig) *TreeView { "keybinding.page-down": PageDownBindingOption, } + hideBindings := map[string]interface{}{ + "keybinding.page-up": true, + "keybinding.page-down": true, + } + for keybinding, action := range bindingSettings { binding, err := config.GetKeyBinding(keybinding) if err != nil { panic(fmt.Errorf("setup error during %s: %w", keybinding, err)) } - t.AddBindingOptions(action(KeyBindingDisplay{KeyBinding: &binding, Selected: false})) + _, hideValue := hideBindings[keybinding] + + t.AddBindingOptions(action(KeyBindingDisplay{KeyBinding: &binding, Selected: false, Hide: hideValue})) } return t @@ -326,8 +333,14 @@ func (t *TreeView) getAbsPositionNode() (node *filetree.FileNode) { return node } + +func (t *TreeView) GetInnerRect() (int,int,int,int) { + x, y, width, height := t.Box.GetInnerRect() + return x, y+1, width, height-1 +} + func (t *TreeView) keyDown() bool { - _, _, _, height := t.Box.GetInnerRect() + _, _, _, height := t.GetInnerRect() // treeIndex is the index about where we are in the current file if t.treeIndex >= t.tree.VisibleSize() { @@ -364,7 +377,7 @@ func (t *TreeView) keyUp() bool { func (t *TreeView) keyRight() bool { node := t.getAbsPositionNode() - _, _, _, height := t.Box.GetInnerRect() + _, _, _, height := t.GetInnerRect() if node == nil { return false } @@ -452,7 +465,7 @@ func (t *TreeView) pageUp() bool { } func (t *TreeView) bufferIndexUpperBound() int { - _, _, _, height := t.Box.GetInnerRect() + _, _, _, height := t.GetInnerRect() return t.bufferIndexLowerBound + height } @@ -464,6 +477,13 @@ func (t *TreeView) Draw(screen tcell.Screen) { treeString := t.tree.StringBetween(t.bufferIndexLowerBound, t.bufferIndexUpperBound(), showAttributes) lines := strings.Split(treeString, "\n") + headerLine := "Filetree" + if showAttributes { + headerLine = fmt.Sprintf("Permission %11s %10s %s", "UID:GID", "Size", "Filetree") + } + + format.PrintLine(screen, headerLine, x, y, len(headerLine), tview.AlignLeft, tcell.StyleDefault) + x, y, width, height = t.GetInnerRect() // update the contents for yIndex, line := range lines { if yIndex >= height { diff --git a/runtime/ui/components/key_config.go b/runtime/ui/components/key_config.go index e5fb064..dd39464 100644 --- a/runtime/ui/components/key_config.go +++ b/runtime/ui/components/key_config.go @@ -2,6 +2,7 @@ package components import ( "fmt" + "strings" "github.com/gdamore/tcell/v2" "github.com/spf13/viper" @@ -10,34 +11,62 @@ import ( // TODO move this to a more appropriate place type KeyConfig struct{} - -type KeyBinding struct{ +type KeyBinding struct { *tcell.EventKey - Display string + Display string } type KeyBindingDisplay struct { *KeyBinding Selected bool - Hide bool + Hide bool } -// just print space key as Space func (kb *KeyBindingDisplay) Name() string { - if kb.Key() == tcell.KeyRune && kb.Rune() == rune(' ') { - return "Space" + s := "" + m := []string{} + kMod := kb.Modifiers() + if kMod&tcell.ModShift != 0 { + m = append(m, "Shift") + } + if kMod&tcell.ModAlt != 0 { + m = append(m, "Alt") + } + if kMod&tcell.ModMeta != 0 { + m = append(m, "Meta") + } + if kMod&tcell.ModCtrl != 0 { + m = append(m, "^") } - return kb.KeyBinding.Name() + ok := false + key := kb.Key() + if s, ok = tcell.KeyNames[key]; !ok { + if key == tcell.KeyRune { + if kb.Rune() == rune(' ') { + s = "Space" + } else { + s = string(kb.Rune()) + } + } else { + s = fmt.Sprintf("Key[%d,%d]", key, int(kb.Rune())) + } + } + if len(m) != 0 { + if kMod&tcell.ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") { + s = s[5:] + } + return fmt.Sprintf("%s%s", strings.Join(m, ""), s) + } + return s } type keyAction func() bool - func NewKeyBinding(name string, key *tcell.EventKey) KeyBinding { return KeyBinding{ EventKey: key, - Display: name, + Display: name, } } @@ -45,8 +74,8 @@ func NewKeyBindingDisplay(k tcell.Key, ch rune, modMask tcell.ModMask, name stri kb := NewKeyBinding(name, tcell.NewEventKey(k, ch, modMask)) return KeyBindingDisplay{ KeyBinding: &kb, - Selected: selected, - Hide: hide, + Selected: selected, + Hide: hide, } } diff --git a/runtime/ui/components/keybinding_primitive.go b/runtime/ui/components/keybinding_primitive.go index 8e1778f..31dd2f9 100644 --- a/runtime/ui/components/keybinding_primitive.go +++ b/runtime/ui/components/keybinding_primitive.go @@ -66,19 +66,34 @@ func (t *KeyMenuView) Draw(screen tcell.Screen) { x, y, width, _ := t.Box.GetInnerRect() // TODO: add logic to highlight selected options - line := []string{} - for _, keyBinding := range t.GetKeyBindings() { - if keyBinding.Hide { + lines := []string{} + keyBindings := t.GetKeyBindings() + for idx, binding := range keyBindings { + if binding.Hide { continue } - formatter := format.StatusControlNormal - if keyBinding.Selected { - formatter = format.StatusControlSelected + displayFormatter := format.StatusControlNormal + keyBindingFormatter := format.StatusControlNormalBold + if binding.Selected { + displayFormatter = format.StatusControlSelected + keyBindingFormatter = format.StatusControlSelectedBold } - line = append(line, formatter(fmt.Sprintf("%s (%s)", keyBinding.Display, keyBinding.Name()))) + postfix := "⎹" + //postfix := "▏" + if idx == len(keyBindings)-1 { + postfix = " " + } + prefix := " " + if idx == 0 { + prefix = "" + } + keyBindingContent := keyBindingFormatter(prefix + binding.Name() + " ") + displayContnet := displayFormatter(binding.Display + postfix) + lines = append(lines, fmt.Sprintf("%s%s", keyBindingContent, displayContnet)) } - - format.PrintLine(screen, strings.Join(line, format.StatusControlNormal(" ▏")), x, y, width, tview.AlignLeft, tcell.StyleDefault) + joinedLine := strings.Join(lines, "") + _, w := tview.PrintWithStyle(screen, joinedLine, x, y, width, tview.AlignLeft, tcell.StyleDefault) + format.PrintLine(screen, format.StatusControlNormal(strings.Repeat(" ", intMax(0,width-w))), x+w, y, width, tview.AlignLeft, tcell.StyleDefault) } diff --git a/runtime/ui/components/layers_primative.go b/runtime/ui/components/layers_primative.go index d73ae56..2317c31 100644 --- a/runtime/ui/components/layers_primative.go +++ b/runtime/ui/components/layers_primative.go @@ -36,55 +36,39 @@ func NewLayerList(model LayersViewModel) *LayerList { Box: tview.NewBox(), cmpIndex: 0, LayersViewModel: model, - keyInputHandler: NewKeyInputHandler(), + keyInputHandler: NewKeyInputHandler(), } } type LayerListViewOption func(ll *LayerList) func UpLayerListBindingOption(k KeyBindingDisplay) LayerListViewOption { - return func (ll *LayerList) { - ll.keyInputHandler.AddBinding(k, func() {ll.keyUp()} ) + return func(ll *LayerList) { + ll.keyInputHandler.AddBinding(k, func() { ll.keyUp() }) } } func DownLayerListBindingOption(k KeyBindingDisplay) LayerListViewOption { - return func (ll *LayerList) { - ll.keyInputHandler.AddBinding(k, func() {ll.keyDown()} ) + return func(ll *LayerList) { + ll.keyInputHandler.AddBinding(k, func() { ll.keyDown() }) } } func PageUpLayerListBindingOption(k KeyBindingDisplay) LayerListViewOption { - return func (ll *LayerList) { - ll.keyInputHandler.AddBinding(k, func() {ll.pageUp()} ) + return func(ll *LayerList) { + ll.keyInputHandler.AddBinding(k, func() { ll.pageUp() }) } } - func PageDownLayerListBindingOption(k KeyBindingDisplay) LayerListViewOption { - return func (ll *LayerList) { - ll.keyInputHandler.AddBinding(k, func() {ll.pageDown()} ) - } -} - -func CompareAllLayerListBindingOption(k KeyBindingDisplay) LayerListViewOption { return func(ll *LayerList) { - ll.keyInputHandler.AddToggleBinding(k, func() { - if ll.GetMode() == viewmodels.CompareSingleLayer { - ll.SwitchMode() - } - }) + ll.keyInputHandler.AddBinding(k, func() { ll.pageDown() }) } } - -func CompareLayerLayerListBindingOption(k KeyBindingDisplay) LayerListViewOption { - return func(ll *LayerList) { - ll.keyInputHandler.AddToggleBinding(k, func() { - if ll.GetMode() == viewmodels.CompareAllLayers { - ll.SwitchMode() - } - }) +func SwitchCompareLayerListBindingOption(k KeyBindingDisplay) LayerListViewOption { + return func(ll *LayerList) { + ll.keyInputHandler.AddToggleBinding(k, func() { ll.SwitchMode() }) } } @@ -96,9 +80,8 @@ func (ll *LayerList) AddBindingOptions(bindingOptions ...LayerListViewOption) *L return ll } - func (ll *LayerList) Setup(config KeyBindingConfig) *LayerList { - + ll.AddBindingOptions( UpLayerListBindingOption(NewKeyBindingDisplay(tcell.KeyUp, rune(0), tcell.ModNone, "", false, true)), UpLayerListBindingOption(NewKeyBindingDisplay(tcell.KeyLeft, rune(0), tcell.ModNone, "", false, true)), @@ -106,21 +89,26 @@ func (ll *LayerList) Setup(config KeyBindingConfig) *LayerList { DownLayerListBindingOption(NewKeyBindingDisplay(tcell.KeyRight, rune(0), tcell.ModNone, "", false, true)), ) - bindingSettings := map[string]func(KeyBindingDisplay) LayerListViewOption { - "keybinding.page-up": PageUpLayerListBindingOption, - "keybinding.page-down": PageDownLayerListBindingOption, - "keybinding.compare-all": CompareAllLayerListBindingOption, - "keybinding.compare-layer": CompareLayerLayerListBindingOption, + bindingSettings := map[string]func(KeyBindingDisplay) LayerListViewOption{ + "keybinding.page-up": PageUpLayerListBindingOption, + "keybinding.page-down": PageDownLayerListBindingOption, + "keybinding.compare-all": SwitchCompareLayerListBindingOption, + } + + hideBindings := map[string]interface{}{ + "keybinding.page-up": true, + "keybinding.page-down": true, } for keybinding, action := range bindingSettings { binding, err := config.GetKeyBinding(keybinding) if err != nil { - panic(fmt.Errorf("setup error during %s: %w", keybinding, err)) + panic(fmt.Errorf("setup error for keybinding: %s: %w", keybinding, err)) // TODO handle this error //return nil } - ll.AddBindingOptions(action(KeyBindingDisplay{KeyBinding: &binding, Selected:false})) + _, hidden := hideBindings[keybinding] + ll.AddBindingOptions(action(KeyBindingDisplay{KeyBinding: &binding, Selected: false, Hide: hidden})) } return ll @@ -145,6 +133,7 @@ func (ll *LayerList) getInputWrapper() inputFn { func (ll *LayerList) Draw(screen tcell.Screen) { ll.Box.Draw(screen) x, y, width, height := ll.Box.GetInnerRect() + compressedView := width < 25 cmpString := " " printableLayers := ll.GetPrintableLayers() @@ -166,8 +155,11 @@ func (ll *LayerList) Draw(screen tcell.Screen) { cmpFormatter = format.CompareBottom } line := fmt.Sprintf("%s %s", cmpFormatter(cmpString), lineFormatter(layer.String())) - printWidth := intMin(len(line),width) - format.PrintLine(screen, line, x, y+yIndex, printWidth, tview.AlignLeft, tcell.StyleDefault) + if compressedView { + line = fmt.Sprintf("%s %s", cmpFormatter(cmpString), lineFormatter(fmt.Sprintf("%d", yIndex + 1))) + } + printWidth := intMin(len(line), width) + format.PrintLine(screen, line, x, y+yIndex, printWidth, tview.AlignLeft, tcell.StyleDefault) } } diff --git a/runtime/ui/components/wrapper_primative.go b/runtime/ui/components/wrapper_primative.go index 83f080f..e0c8f0a 100644 --- a/runtime/ui/components/wrapper_primative.go +++ b/runtime/ui/components/wrapper_primative.go @@ -6,6 +6,7 @@ import ( "github.com/gdamore/tcell/v2" "github.com/rivo/tview" + "github.com/wagoodman/dive/runtime/ui/format" ) // This was pretty helpful: https://github.com/rivo/tview/wiki/Primitives @@ -40,7 +41,7 @@ func NewWrapper(title, subtitle string, inner wrapable) *Wrapper { flex: flex, title: title, subtitle: subtitle, - titleTextView: tview.NewTextView(), + titleTextView: tview.NewTextView().SetDynamicColors(true), subtitleTextView: tview.NewTextView().SetText(subtitle), inner: inner, visible: Always(true), @@ -75,9 +76,12 @@ func (b *Wrapper) Draw(screen tcell.Screen) { if b.title != "" { b.titleTextView.Draw(screen) x, y, width, _ := b.titleRightBox.GetRect() + boarderRune := tview.BoxDrawingsLightHorizontal + if b.HasFocus() { + boarderRune = tview.BoxDrawingsHeavyHorizontal + } for cx := x; cx < x+width; cx++ { - // TODO: swap for bold when focused (tview.BoxDrawingsHeavyHorizontal) - screen.SetContent(cx, y, tview.BoxDrawingsLightHorizontal, nil, tcell.StyleDefault) + screen.SetContent(cx, y, boarderRune, nil, tcell.StyleDefault) } } if b.subtitle != "" { @@ -110,15 +114,17 @@ func (b *Wrapper) InputHandler() func(event *tcell.EventKey, setFocus func(p tvi func (b *Wrapper) setTitle(hasFocus bool) { prefix := "" + postfix := strings.Repeat(string(tview.BoxDrawingsLightHorizontal), 10) if hasFocus { prefix = "● " + postfix = strings.Repeat(string(tview.BoxDrawingsHeavyHorizontal), 10) } - // TODO: swap for bold when focused (tview.BoxDrawingsHeavyHorizontal) - postfix := strings.Repeat(string(tview.BoxDrawingsLightHorizontal), 10) - title := fmt.Sprintf("│ %s%s ├%s", prefix, b.title, postfix) + content := format.Header(fmt.Sprintf("%s%s", prefix, b.title)) + title := fmt.Sprintf("│ %s ├%s", content, postfix) if hasFocus { - // TODO: add bold wrapper + content = format.Header(fmt.Sprintf("%s%s", prefix, b.title)) + title = fmt.Sprintf("┃ %s ┣%s", content, postfix) } b.titleTextView.SetText(title) diff --git a/runtime/ui/format/format.go b/runtime/ui/format/format.go index 690c0e5..80ba230 100644 --- a/runtime/ui/format/format.go +++ b/runtime/ui/format/format.go @@ -61,16 +61,18 @@ func GenerateWholeLineFormatter(fg, bg, flags string) Formatter { var ( // Bolds text - Header Formatter = GenerateFormatter("", "", "b") - Normal Formatter = GenerateFormatter("", "", "") - Selected Formatter = GenerateFormatter("", "", "rb") - StatusSelected Formatter = GenerateFormatter(colorTranslate(tcell.ColorWhite), colorTranslate(tcell.ColorDarkMagenta), "") - StatusNormal Formatter = GenerateFormatter("", "", "r") - StatusControlSelected Formatter = GenerateFormatter(colorTranslate(tcell.ColorWhite), colorTranslate(tcell.ColorDarkMagenta), "b") - StatusControlNormal Formatter = GenerateFormatter("", "", "rb") - CompareTop Formatter = GenerateFormatter("", colorTranslate(tcell.ColorDarkMagenta), "") - CompareBottom Formatter = GenerateFormatter("", colorTranslate(tcell.ColorDarkGreen), "") - FileTreeSelected Formatter = func(s string) string { return boldReplace(GenerateWholeLineFormatter("", "", "rb")(s)) } + Header Formatter = GenerateFormatter("", "", "b") + Normal Formatter = GenerateFormatter("", "", "") + Selected Formatter = GenerateFormatter("", "", "rb") + StatusSelected Formatter = GenerateFormatter(colorTranslate(tcell.ColorWhite), colorTranslate(tcell.ColorDarkMagenta), "") + StatusNormal Formatter = GenerateFormatter("", "", "r") + StatusControlSelected Formatter = GenerateFormatter(colorTranslate(tcell.ColorWhite), colorTranslate(tcell.ColorDarkMagenta), "") + StatusControlSelectedBold Formatter = GenerateFormatter(colorTranslate(tcell.ColorWhite), colorTranslate(tcell.ColorDarkMagenta), "b") + StatusControlNormal Formatter = GenerateFormatter("", "", "r") + StatusControlNormalBold Formatter = GenerateFormatter("", "", "rb") + CompareTop Formatter = GenerateFormatter("", colorTranslate(tcell.ColorDarkMagenta), "") + CompareBottom Formatter = GenerateFormatter("", colorTranslate(tcell.ColorDarkGreen), "") + FileTreeSelected Formatter = func(s string) string { return boldReplace(GenerateWholeLineFormatter("", "", "rb")(s)) } // filediff types Added Formatter = GenerateFormatter(colorTranslate(tcell.ColorGreen), "", "") @@ -78,8 +80,9 @@ var ( Modified Formatter = GenerateFormatter(colorTranslate(tcell.ColorYellow), "", "") // Styles these are needed to completely color a line - SelectedStyle tcell.Style = tcell.Style{}.Bold(true).Reverse(true) - MenuStyle tcell.Style = tcell.Style{}.Reverse(true) + HeaderStyle tcell.Style = tcell.Style{}.Bold(true).Reverse(true) + SelectedStyle tcell.Style = tcell.Style{}.Bold(true).Reverse(true) + MenuStyle tcell.Style = tcell.Style{}.Reverse(true) SelectedMenuStyle tcell.Style = tcell.Style{}.Background(tcell.ColorDarkBlue).Foreground(tcell.ColorWhite).Bold(true) ) |