Skip to content

Commit

Permalink
POC displaying a graph
Browse files Browse the repository at this point in the history
  • Loading branch information
spacez320 committed Dec 26, 2023
1 parent 7c90854 commit b1d027f
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 25 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/gdamore/tcell/v2 v2.6.1-0.20231203215052-2917c3801e73 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mum4k/termdash v0.18.0 // indirect
github.com/rivo/tview v0.0.0-20231206124440-5f078138442e // indirect
github.com/rivo/uniseg v0.4.3 // indirect
golang.org/x/sys v0.14.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mum4k/termdash v0.18.0 h1:wpy3FKcVV5s2TOoMTKzqQXwL5VClZIlNrRqZDpeIzBA=
github.com/mum4k/termdash v0.18.0/go.mod h1:VWL18wLZDKVKF/f4TkMRiKZb9Eg8Ax99PtNuGuRAguw=
github.com/rivo/tview v0.0.0-20231206124440-5f078138442e h1:mPy47VW9tkqImnSPgcjnEHJuG3XHDBtXj2hDb1qBrRs=
github.com/rivo/tview v0.0.0-20231206124440-5f078138442e/go.mod h1:c0SPlNPXkM+/Zgjn/0vD3W0Ds1yxstN7lpquqLDpWCg=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
Expand Down
7 changes: 5 additions & 2 deletions internal/lib/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ require (
golang.org/x/exp v0.0.0-20231127185646-65229373498e
)

require pkg/storage v0.0.0
require (
github.com/gdamore/tcell/v2 v2.6.1-0.20231203215052-2917c3801e73
github.com/mum4k/termdash v0.18.0
pkg/storage v0.0.0
)

require (
github.com/gdamore/encoding v1.0.0 // indirect
github.com/gdamore/tcell/v2 v2.6.1-0.20231203215052-2917c3801e73 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
Expand Down
3 changes: 3 additions & 0 deletions internal/lib/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.6.1-0.20231203215052-2917c3801e73 h1:SeDV6ZUSVlTAUUPdMzPXgMyj96z+whQJRRUff8dIeic=
github.com/gdamore/tcell/v2 v2.6.1-0.20231203215052-2917c3801e73/go.mod h1:pwzJMyH4Hd0AZMJkWQ+/g01dDvYWEvmJuaiRU71Xl8k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mum4k/termdash v0.18.0 h1:wpy3FKcVV5s2TOoMTKzqQXwL5VClZIlNrRqZDpeIzBA=
github.com/mum4k/termdash v0.18.0/go.mod h1:VWL18wLZDKVKF/f4TkMRiKZb9Eg8Ax99PtNuGuRAguw=
github.com/rivo/tview v0.0.0-20231206124440-5f078138442e h1:mPy47VW9tkqImnSPgcjnEHJuG3XHDBtXj2hDb1qBrRs=
github.com/rivo/tview v0.0.0-20231206124440-5f078138442e/go.mod h1:c0SPlNPXkM+/Zgjn/0vD3W0Ds1yxstN7lpquqLDpWCg=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
Expand Down
162 changes: 143 additions & 19 deletions internal/lib/results.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
//
// Results management.
//
// Managing results involves:
//
// - Organizing a storage of results.
// - Managing the TUI libraries, rendering, and interaction for results.
// - Finding a place for accessory output, like logs.

package lib

import (
"context"
"fmt"
"os"
"strconv"
Expand All @@ -14,37 +21,103 @@ import (
"pkg/storage"

"github.com/gdamore/tcell/v2"
"github.com/mum4k/termdash"
"github.com/mum4k/termdash/cell"
"github.com/mum4k/termdash/container"
termdashTcell "github.com/mum4k/termdash/terminal/tcell"
"github.com/mum4k/termdash/terminal/terminalapi"
"github.com/mum4k/termdash/widgetapi"
"github.com/mum4k/termdash/widgets/sparkline"
"github.com/rivo/tview"
)

// Represents the display mode.
type display_ int

const (
LOGS_SIZE = 1 // Proportional size of the logs widget.
RESULTS_SIZE = 3 // Proportional size of the results widget.
TABLE_PADDING = 2 // Padding for table cell entries.
)

const (
DISPLAY_RAW display_ = iota + 1 // Used for direct output.
DISPLAY_TVIEW // Used when tview is the TUI driver.
DISPLAY_TERMDASH // Used when termdash is the TUI driver.

)

var (
app *tview.Application // Application for display.
results storage.Results // Stored results.
// Application for display. Only applicable for tview result modes.
app *tview.Application
// Display mode, dictated by the results.
mode display_
// Stored results.
results storage.Results

// Widget for displaying logs. Publicly offered to allow log configuration.
// Only applicable for tview result modes.
LogsView *tview.TextView
)

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Private
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Set-up the sync for logs used by some result modes.
func init() {
// Initialized specifically for showing logs in a tview pane. Currently,
// tview is the only supported display backend that supports logging, and
// termdash will not show logs.
//
// Initializing this is harmless, even if tview won't be used.
//
// TODO This should be probably be managed outside of init and should be made
// display mode agnostic, if possible.
LogsView = tview.NewTextView().SetChangedFunc(func() { app.Draw() })
LogsView.SetBorder(true).SetTitle("Logs")
}

// Sets-up the flex box, which defines the overall layout.
func initDisplay(resultsView tview.Primitive, logsView tview.Primitive) {
// Sets-up the termdash display and renders a widget.
func initDisplayTermdash(resultsWidget widgetapi.Widget) {
// Set-up the context and enable it to close on key-press.
ctx, cancel := context.WithCancel(context.Background())

// Set-up the layout.
t, err := termdashTcell.New()
e(err)

// Render the widget.
c, err := container.New(t, container.PlaceWidget(resultsWidget))
e(err)

// Run the display.
termdash.Run(ctx, t, c, termdash.KeyboardSubscriber(
func(k *terminalapi.Keyboard) {
if k.Key == 'q' {
cancel()
t.Close()
os.Exit(0)
}
},
))
}

// Sets-up the tview flex box with results and logs views, which defines the
// overall layout.
//
// Note that the app needs to be run separately from initialization in the
// coroutine display function.
func initDisplayTview(resultsView tview.Primitive, logsView tview.Primitive) {
// Initialize the app.
app = tview.NewApplication()

// Set-up the layout and apply views.
flexBox := tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(resultsView, 0, RESULTS_SIZE, false).
AddItem(logsView, 0, LOGS_SIZE, false)

app.SetRoot(flexBox, true).SetFocus(resultsView)
}

Expand All @@ -54,11 +127,23 @@ func display(f func()) {
// Execute the update function.
go func() { f() }()

// Start the display.
err := app.Run()
e(err)
switch mode {
case DISPLAY_TVIEW:
// Start the tview-specific display.
err := app.Run()
e(err)
case DISPLAY_TERMDASH:
// Start the termdash-specific display.
// Nothing to do, yet.
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Public
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Adds a result to the result store.
//
// TODO In the future, multiple result stores could be implemented by making
Expand Down Expand Up @@ -108,15 +193,34 @@ func TokenizeResult(result string) (parsedResult []interface{}) {
return
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Result Modes
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Presents raw output.
func RawResults() {
mode = DISPLAY_RAW

go func() {
for {
fmt.Println(<-storage.PutEvents)
}
}()
}

// Update the results pane with new results as they are generated.
func StreamResults() {
mode = DISPLAY_TVIEW

resultsView := tview.NewTextView().SetChangedFunc(
func() {
app.Draw()
})
resultsView.SetBorder(true).SetTitle("Results")

initDisplay(resultsView, LogsView)
initDisplayTview(resultsView, LogsView)

display(
func() {
Expand All @@ -127,21 +231,14 @@ func StreamResults() {
)
}

// Presents raw output.
func RawResults() {
go func() {
for {
fmt.Println(<-storage.PutEvents)
}
}()
}

// Creates a table of results for the results pane.
func TableResults() {
mode = DISPLAY_TVIEW

resultsView := tview.NewTable().SetBorders(true)
tableCellPadding := strings.Repeat(" ", TABLE_PADDING)

initDisplay(resultsView, LogsView)
initDisplayTview(resultsView, LogsView)

resultsView.SetDoneFunc(
func(key tcell.Key) {
Expand Down Expand Up @@ -180,6 +277,8 @@ func TableResults() {
row.SetCellSimple(i, j, tableCellPadding+nextCellContent+tableCellPadding)
}

// Re-draw the app with the new results row.
app.Draw()
i += 1
}
},
Expand All @@ -189,3 +288,28 @@ func TableResults() {
err := app.Run()
e(err)
}

// Creates a graph of results for the results pane.
func GraphResults() {
mode = DISPLAY_TERMDASH

graph, err := sparkline.New(
sparkline.Label("Test Sparkline", cell.FgColor(cell.ColorNumber(33))),
sparkline.Color(cell.ColorGreen),
)
e(err)

display(
func() {
for {
next := <-storage.PutEvents

graph.Add([]int{int(100 * next.Values[9].(float64))})
}

graph.Add([]int{1, 2, 3})
},
)

initDisplayTermdash(graph)
}
20 changes: 16 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const (
RESULT_MODE_RAW resultMode_ = iota + 1 // For running in 'raw' result mode.
RESULT_MODE_STREAM // For running in 'stream' result mode.
RESULT_MODE_TABLE // For running in 'table' result mode.
RESULT_MODE_GRAPH // For running in 'graph' result mode.
)

var (
Expand Down Expand Up @@ -124,25 +125,36 @@ func main() {
// Execute result viewing.

if !silent {
switch {
case resultMode == int(RESULT_MODE_RAW):
switch resultMode {
case int(RESULT_MODE_RAW):
lib.RawResults()
case resultMode == int(RESULT_MODE_STREAM):
case int(RESULT_MODE_STREAM):
// Pass logs into the logs view pane.
slog.SetDefault(slog.New(slog.NewTextHandler(
lib.LogsView,
&slog.HandlerOptions{Level: logLevelStrToSlogLevel[logLevel]},
)))

lib.StreamResults()
case resultMode == int(RESULT_MODE_TABLE):
case int(RESULT_MODE_TABLE):
// Pass logs into the logs view pane.
slog.SetDefault(slog.New(slog.NewTextHandler(
lib.LogsView,
&slog.HandlerOptions{Level: logLevelStrToSlogLevel[logLevel]},
)))

lib.TableResults()
case int(RESULT_MODE_GRAPH):
// Pass logs into the logs view pane.
//
// FIXME Log management for termdash applications doesn't work the same
// way and needs to be managed.
// slog.SetDefault(slog.New(slog.NewTextHandler(
// lib.LogsView,
// &slog.HandlerOptions{Level: logLevelStrToSlogLevel[logLevel]},
// )))

lib.GraphResults()
default:
slog.Error(fmt.Sprintf("Invalid result mode: %d\n", resultMode))
os.Exit(1)
Expand Down

0 comments on commit b1d027f

Please sign in to comment.