Short status (#419)

Co-authored-by: Martin Cross <martinidc1992@gmail.com>
pull/467/head
Martin Cross 10 months ago committed by GitHub
parent 07f26c1e91
commit dffe6970aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -38,6 +38,10 @@ gui:
expandFocusedSidePanel: false
# Determines which screen mode will be used on startup
screenMode: "normal" # one of 'normal' | 'half' | 'fullscreen'
# Determines the style of the container status and container health display in the
# containers panel. "long": full words (default), "short": one or two characters,
# "icon": unicode emoji.
containerStatusHealthStyle: "long"
logs:
timestamps: false
since: '60m' # set to '' to show all logs

@ -133,6 +133,11 @@ type GuiConfig struct {
// ScreenMode allow user to specify which screen mode will be used on startup
ScreenMode string `yaml:"screenMode,omitempty"`
// Determines the style of the container status and container health display in the
// containers panel. "long": full words (default), "short": one or two characters,
// "icon": unicode emoji.
ContainerStatusHealthStyle string `yaml:"containerStatusHealthStyle"`
}
// CommandTemplatesConfig determines what commands actually get called when we
@ -358,14 +363,15 @@ func GetDefaultConfig() UserConfig {
InactiveBorderColor: []string{"default"},
OptionsTextColor: []string{"blue"},
},
ShowAllContainers: false,
ReturnImmediately: false,
WrapMainPanel: true,
LegacySortContainers: false,
SidePanelWidth: 0.3333,
ShowBottomLine: true,
ExpandFocusedSidePanel: false,
ScreenMode: "normal",
ShowAllContainers: false,
ReturnImmediately: false,
WrapMainPanel: true,
LegacySortContainers: false,
SidePanelWidth: 0.3333,
ShowBottomLine: true,
ExpandFocusedSidePanel: false,
ScreenMode: "normal",
ContainerStatusHealthStyle: "long",
},
ConfirmOnQuit: false,
Logs: LogsConfig{

@ -96,7 +96,9 @@ func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container]
return true
},
GetTableCells: presentation.GetContainerDisplayStrings,
GetTableCells: func(container *commands.Container) []string {
return presentation.GetContainerDisplayStrings(&gui.Config.UserConfig.Gui, container)
},
}
}

@ -9,14 +9,15 @@ import (
dockerTypes "github.com/docker/docker/api/types"
"github.com/fatih/color"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/samber/lo"
)
func GetContainerDisplayStrings(container *commands.Container) []string {
func GetContainerDisplayStrings(guiConfig *config.GuiConfig, container *commands.Container) []string {
return []string{
getContainerDisplayStatus(container),
getContainerDisplaySubstatus(container),
getContainerDisplayStatus(guiConfig, container),
getContainerDisplaySubstatus(guiConfig, container),
container.Name,
getDisplayCPUPerc(container),
utils.ColoredString(displayPorts(container), color.FgYellow),
@ -52,12 +53,44 @@ func displayPorts(c *commands.Container) string {
}
// getContainerDisplayStatus returns the colored status of the container
func getContainerDisplayStatus(c *commands.Container) string {
return utils.ColoredString(c.Container.State, getContainerColor(c))
func getContainerDisplayStatus(guiConfig *config.GuiConfig, c *commands.Container) string {
shortStatusMap := map[string]string{
"paused": "P",
"exited": "X",
"created": "C",
"removing": "RM",
"restarting": "RS",
"running": "R",
"dead": "D",
}
iconStatusMap := map[string]rune{
"paused": '◫',
"exited": '',
"created": '+',
"removing": '',
"restarting": '⟳',
"running": '▶',
"dead": '!',
}
var containerState string
switch guiConfig.ContainerStatusHealthStyle {
case "short":
containerState = shortStatusMap[c.Container.State]
case "icon":
containerState = string(iconStatusMap[c.Container.State])
case "long":
fallthrough
default:
containerState = c.Container.State
}
return utils.ColoredString(containerState, getContainerColor(c))
}
// GetDisplayStatus returns the exit code if the container has exited, and the health status if the container is running (and has a health check)
func getContainerDisplaySubstatus(c *commands.Container) string {
func getContainerDisplaySubstatus(guiConfig *config.GuiConfig, c *commands.Container) string {
if !c.DetailsLoaded() {
return ""
}
@ -68,13 +101,13 @@ func getContainerDisplaySubstatus(c *commands.Container) string {
fmt.Sprintf("(%s)", strconv.Itoa(c.Details.State.ExitCode)), getContainerColor(c),
)
case "running":
return getHealthStatus(c)
return getHealthStatus(guiConfig, c)
default:
return ""
}
}
func getHealthStatus(c *commands.Container) string {
func getHealthStatus(guiConfig *config.GuiConfig, c *commands.Container) string {
if !c.DetailsLoaded() {
return ""
}
@ -88,8 +121,32 @@ func getHealthStatus(c *commands.Container) string {
if c.Details.State.Health == nil {
return ""
}
healthStatus := c.Details.State.Health.Status
if healthStatusColor, ok := healthStatusColorMap[healthStatus]; ok {
shortHealthStatusMap := map[string]string{
"healthy": "H",
"unhealthy": "U",
"starting": "S",
}
iconHealthStatusMap := map[string]rune{
"healthy": '✔',
"unhealthy": '?',
"starting": '…',
}
var healthStatus string
switch guiConfig.ContainerStatusHealthStyle {
case "short":
healthStatus = shortHealthStatusMap[c.Details.State.Health.Status]
case "icon":
healthStatus = string(iconHealthStatusMap[c.Details.State.Health.Status])
case "long":
fallthrough
default:
healthStatus = c.Details.State.Health.Status
}
if healthStatusColor, ok := healthStatusColorMap[c.Details.State.Health.Status]; ok {
return utils.ColoredString(fmt.Sprintf("(%s)", healthStatus), healthStatusColor)
}
return ""

@ -3,13 +3,26 @@ package presentation
import (
"github.com/fatih/color"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/utils"
)
func GetServiceDisplayStrings(service *commands.Service) []string {
func GetServiceDisplayStrings(guiConfig *config.GuiConfig, service *commands.Service) []string {
if service.Container == nil {
var containerState string
switch guiConfig.ContainerStatusHealthStyle {
case "short":
containerState = "n"
case "icon":
containerState = "."
case "long":
fallthrough
default:
containerState = "none"
}
return []string{
utils.ColoredString("none", color.FgBlue),
utils.ColoredString(containerState, color.FgBlue),
"",
service.Name,
"",
@ -20,8 +33,8 @@ func GetServiceDisplayStrings(service *commands.Service) []string {
container := service.Container
return []string{
getContainerDisplayStatus(container),
getContainerDisplaySubstatus(container),
getContainerDisplayStatus(guiConfig, container),
getContainerDisplaySubstatus(guiConfig, container),
service.Name,
getDisplayCPUPerc(container),
utils.ColoredString(displayPorts(container), color.FgYellow),

@ -74,7 +74,9 @@ func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
return a.Name < b.Name
},
GetTableCells: presentation.GetServiceDisplayStrings,
GetTableCells: func(service *commands.Service) []string {
return presentation.GetServiceDisplayStrings(&gui.Config.UserConfig.Gui, service)
},
Hide: func() bool {
return !gui.DockerCommand.InDockerComposeProject
},

@ -14,6 +14,7 @@ import (
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"
"github.com/mattn/go-runewidth"
// "github.com/jesseduffield/yaml"
@ -41,10 +42,10 @@ func SplitLines(multilineString string) []string {
// WithPadding pads a string as much as you want
func WithPadding(str string, padding int) string {
uncoloredStr := Decolorise(str)
if padding < len(uncoloredStr) {
if padding < runewidth.StringWidth(uncoloredStr) {
return str
}
return str + strings.Repeat(" ", padding-len(uncoloredStr))
return str + strings.Repeat(" ", padding-runewidth.StringWidth(uncoloredStr))
}
// ColoredString takes a string and a colour attribute and returns a colored
@ -143,54 +144,52 @@ func Max(x, y int) int {
}
// RenderTable takes an array of string arrays and returns a table containing the values
func RenderTable(stringArrays [][]string) (string, error) {
if len(stringArrays) == 0 {
func RenderTable(rows [][]string) (string, error) {
if len(rows) == 0 {
return "", nil
}
if !displayArraysAligned(stringArrays) {
if !displayArraysAligned(rows) {
return "", errors.New("Each item must return the same number of strings to display")
}
padWidths := getPadWidths(stringArrays)
paddedDisplayStrings := getPaddedDisplayStrings(stringArrays, padWidths)
columnPadWidths := getPadWidths(rows)
paddedDisplayRows := getPaddedDisplayStrings(rows, columnPadWidths)
return strings.Join(paddedDisplayStrings, "\n"), nil
return strings.Join(paddedDisplayRows, "\n"), nil
}
// Decolorise strips a string of color
func Decolorise(str string) string {
re := regexp.MustCompile(`\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]`)
re := regexp.MustCompile(`\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mK]`)
return re.ReplaceAllString(str, "")
}
func getPadWidths(stringArrays [][]string) []int {
if len(stringArrays[0]) <= 1 {
func getPadWidths(rows [][]string) []int {
if len(rows[0]) <= 1 {
return []int{}
}
padWidths := make([]int, len(stringArrays[0])-1)
for i := range padWidths {
for _, strings := range stringArrays {
uncoloredString := Decolorise(strings[i])
if len(uncoloredString) > padWidths[i] {
padWidths[i] = len(uncoloredString)
columnPadWidths := make([]int, len(rows[0])-1)
for i := range columnPadWidths {
for _, cells := range rows {
uncoloredCell := Decolorise(cells[i])
if runewidth.StringWidth(uncoloredCell) > columnPadWidths[i] {
columnPadWidths[i] = runewidth.StringWidth(uncoloredCell)
}
}
}
return padWidths
return columnPadWidths
}
func getPaddedDisplayStrings(stringArrays [][]string, padWidths []int) []string {
paddedDisplayStrings := make([]string, len(stringArrays))
for i, stringArray := range stringArrays {
if len(stringArray) == 0 {
continue
}
for j, padWidth := range padWidths {
paddedDisplayStrings[i] += WithPadding(stringArray[j], padWidth) + " "
func getPaddedDisplayStrings(rows [][]string, columnPadWidths []int) []string {
paddedDisplayRows := make([]string, len(rows))
for i, cells := range rows {
for j, columnPadWidth := range columnPadWidths {
paddedDisplayRows[i] += WithPadding(cells[j], columnPadWidth) + " "
}
paddedDisplayStrings[i] += stringArray[len(padWidths)]
paddedDisplayRows[i] += cells[len(columnPadWidths)]
}
return paddedDisplayStrings
return paddedDisplayRows
}
// displayArraysAligned returns true if every string array returned from our

Loading…
Cancel
Save