summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordwillist <dthornton@vmware.com>2021-01-18 20:07:33 -0500
committerdwillist <dthornton@vmware.com>2021-01-18 20:07:33 -0500
commit9f745c7c8bd037e911c7c5aa6a78c509a98304d9 (patch)
tree9a405130f7892be3bef815978d14dae8fb55af4f
parentcf5af7d5b52320e3b2e8083a08468e73d2a98b08 (diff)
update styling and improve keybinding display
Signed-off-by: dwillist <dthornton@vmware.com>
-rw-r--r--cmd/root.go14
-rw-r--r--runtime/ui/app.go7
-rw-r--r--runtime/ui/components/filetree_primative.go28
-rw-r--r--runtime/ui/components/key_config.go53
-rw-r--r--runtime/ui/components/keybinding_primitive.go33
-rw-r--r--runtime/ui/components/layers_primative.go68
-rw-r--r--runtime/ui/components/wrapper_primative.go20
-rw-r--r--runtime/ui/format/format.go27
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)
)