2
0
mirror of https://github.com/hibiken/asynq.git synced 2025-10-03 17:22:01 +08:00

(cli): Allow different styles to be used in modal row

This commit is contained in:
Ken Hibino
2022-05-27 16:08:57 -07:00
parent a57c1aacb8
commit 165e9f3fba
2 changed files with 83 additions and 39 deletions

View File

@@ -535,50 +535,71 @@ func drawTaskModal(d *ScreenDrawer, state *State) {
task := state.selectedTask task := state.selectedTask
if task == nil { if task == nil {
// task no longer found // task no longer found
contents := []*rowContent{ fns := []func(d *modalRowDrawer){
{"=== Task Summary ===", baseStyle.Bold(true)}, func(d *modalRowDrawer) { d.Print("=== Task Summary ===", baseStyle.Bold(true)) },
{"", baseStyle}, func(d *modalRowDrawer) { d.Print("", baseStyle) },
{fmt.Sprintf("Task %q no longer exists", state.taskID), baseStyle}, func(d *modalRowDrawer) { d.Print(fmt.Sprintf("Task %q no longer exists", state.taskID), baseStyle) },
} }
withModal(d, contents) withModal(d, fns)
return return
} }
contents := []*rowContent{ fns := []func(d *modalRowDrawer){
{"=== Task Summary ===", baseStyle.Bold(true)}, func(d *modalRowDrawer) { d.Print("=== Task Summary ===", baseStyle.Bold(true)) },
{"", baseStyle}, func(d *modalRowDrawer) { d.Print("", baseStyle) },
{fmt.Sprintf("ID: %s", task.ID), baseStyle}, func(d *modalRowDrawer) {
{fmt.Sprintf("Type: %s", task.Type), baseStyle}, d.Print("ID: ", labelStyle)
{fmt.Sprintf("State: %s", task.State.String()), baseStyle}, d.Print(task.ID, baseStyle)
{fmt.Sprintf("Queue: %s", task.Queue), baseStyle}, },
{fmt.Sprintf("Retried: %d/%d", task.Retried, task.MaxRetry), baseStyle}, func(d *modalRowDrawer) {
d.Print("Type: ", labelStyle)
d.Print(task.Type, baseStyle)
},
func(d *modalRowDrawer) {
d.Print("State: ", labelStyle)
d.Print(task.State.String(), baseStyle)
},
func(d *modalRowDrawer) {
d.Print("Queue: ", labelStyle)
d.Print(task.Queue, baseStyle)
},
func(d *modalRowDrawer) {
d.Print("Retry: ", labelStyle)
d.Print(fmt.Sprintf("%d/%d", task.Retried, task.MaxRetry), baseStyle)
},
} }
if task.LastErr != "" { if task.LastErr != "" {
contents = append(contents, &rowContent{ fns = append(fns, func(d *modalRowDrawer) {
fmt.Sprintf("Last Failure: %s", task.LastErr), d.Print("Last Failure: ", labelStyle)
baseStyle, d.Print(task.LastErr, baseStyle)
}) })
contents = append(contents, &rowContent{ fns = append(fns, func(d *modalRowDrawer) {
fmt.Sprintf("Last Failure Time: %v", task.LastFailedAt), d.Print("Last Failure Time: ", labelStyle)
baseStyle, d.Print(fmt.Sprintf("%v", task.LastFailedAt), baseStyle)
}) })
} }
if !task.NextProcessAt.IsZero() { if !task.NextProcessAt.IsZero() {
contents = append(contents, &rowContent{ fns = append(fns, func(d *modalRowDrawer) {
fmt.Sprintf("Next Process Time: %v", task.NextProcessAt), d.Print("Next Process Time: ", labelStyle)
baseStyle, d.Print(fmt.Sprintf("%v", task.NextProcessAt), baseStyle)
}) })
} }
if !task.CompletedAt.IsZero() { if !task.CompletedAt.IsZero() {
contents = append(contents, &rowContent{ fns = append(fns, func(d *modalRowDrawer) {
fmt.Sprintf("Completion Time: %v", task.CompletedAt), d.Print("Completion Time: ", labelStyle)
baseStyle, d.Print(fmt.Sprintf("%v", task.CompletedAt), baseStyle)
}) })
} }
contents = append(contents, &rowContent{ fns = append(fns, func(d *modalRowDrawer) {
fmt.Sprintf("Payload: %s", formatByteSlice(task.Payload)), d.Print("Payload: ", labelStyle)
baseStyle, d.Print(formatByteSlice(task.Payload), baseStyle)
}) })
withModal(d, contents) if task.Result != nil {
fns = append(fns, func(d *modalRowDrawer) {
d.Print("Result: ", labelStyle)
d.Print(formatByteSlice(task.Result), baseStyle)
})
}
withModal(d, fns)
} }
// Reports whether the given byte slice is printable (i.e. human readable) // Reports whether the given byte slice is printable (i.e. human readable)
@@ -608,12 +629,25 @@ func formatByteSlice(data []byte) string {
return string(data) return string(data)
} }
type rowContent struct { type modalRowDrawer struct {
s string // should not include newline d *ScreenDrawer
style tcell.Style width int // current width occupied by content
maxWidth int
} }
func withModal(d *ScreenDrawer, contents []*rowContent) { // Note: s should not include newline
func (d *modalRowDrawer) Print(s string, style tcell.Style) {
if d.width >= d.maxWidth {
return // no longer write to this row
}
if d.width+runewidth.StringWidth(s) > d.maxWidth {
s = truncate(s, d.maxWidth-d.width)
}
d.d.Print(s, style)
}
// withModal draws a modal with the given functions row by row.
func withModal(d *ScreenDrawer, rowPrintFns []func(d *modalRowDrawer)) {
w, h := d.Screen().Size() w, h := d.Screen().Size()
var ( var (
modalWidth = int(math.Floor(float64(w) * 0.6)) modalWidth = int(math.Floor(float64(w) * 0.6))
@@ -629,16 +663,18 @@ func withModal(d *ScreenDrawer, contents []*rowContent) {
d.Print(strings.Repeat(string(tcell.RuneHLine), modalWidth-2), baseStyle) d.Print(strings.Repeat(string(tcell.RuneHLine), modalWidth-2), baseStyle)
d.Print(string(tcell.RuneURCorner), baseStyle) d.Print(string(tcell.RuneURCorner), baseStyle)
d.NL() d.NL()
contentWidth := modalWidth - 4 /* borders + paddings */ rowDrawer := modalRowDrawer{
d: d,
width: 0,
maxWidth: modalWidth - 4, /* borders + paddings */
}
for i := 1; i < modalHeight-1; i++ { for i := 1; i < modalHeight-1; i++ {
d.Goto(colOffset, rowOffset+i) d.Goto(colOffset, rowOffset+i)
d.Print(fmt.Sprintf("%c ", tcell.RuneVLine), baseStyle) d.Print(fmt.Sprintf("%c ", tcell.RuneVLine), baseStyle)
cnt := &rowContent{strings.Repeat(" ", contentWidth), baseStyle} if i < len(rowPrintFns) {
if i <= len(contents) { rowPrintFns[i-1](&rowDrawer)
cnt = contents[i-1]
cnt.s = adjustWidth(cnt.s, contentWidth)
} }
d.Print(truncate(cnt.s, contentWidth), cnt.style) d.FillUntil(' ', baseStyle, colOffset+modalWidth-2)
d.Print(fmt.Sprintf(" %c", tcell.RuneVLine), baseStyle) d.Print(fmt.Sprintf(" %c", tcell.RuneVLine), baseStyle)
d.NL() d.NL()
} }

View File

@@ -47,6 +47,14 @@ func (d *ScreenDrawer) FillLine(r rune, style tcell.Style) {
d.NL() d.NL()
} }
func (d *ScreenDrawer) FillUntil(r rune, style tcell.Style, limit int) {
if d.l.col > limit {
return // already passed the limit
}
s := strings.Repeat(string(r), limit-d.l.col)
d.Print(s, style)
}
// NL adds a newline (i.e., moves to the next line). // NL adds a newline (i.e., moves to the next line).
func (d *ScreenDrawer) NL() { func (d *ScreenDrawer) NL() {
d.l.row++ d.l.row++