From b9ffcb4b5a6b5d42f1ffd377370565100748dacf Mon Sep 17 00:00:00 2001 From: Andrew Lee <32912555+candrewlee14@users.noreply.github.com> Date: Fri, 1 Jul 2022 10:22:13 -0600 Subject: [PATCH] fix: improve display for strings and numbers in v1 shell tables (#420) * fix: improve alignment for strings and numbers * add scientific toggle command for table format * enter altscreen when in table format interactive mode * chore: run go mod tidy --- clients/v1_shell/autocomplete.go | 5 ++-- clients/v1_shell/table_model.go | 43 ++++++++++++++++++++++++-------- clients/v1_shell/v1_shell.go | 19 ++++++++++++-- go.mod | 2 +- 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/clients/v1_shell/autocomplete.go b/clients/v1_shell/autocomplete.go index 47d5ce4..d91f8cb 100644 --- a/clients/v1_shell/autocomplete.go +++ b/clients/v1_shell/autocomplete.go @@ -118,8 +118,9 @@ func newSugNodeFn(subsugs ...string) subsuggestFnType { func (c *Client) completer(d prompt.Document) []prompt.Suggest { // the commented-out lines are unsupported in 2.x suggestions := map[string]SuggestNode{ - "use": {Description: "Set current database", subsuggestFn: c.suggestUse}, - "pretty": {Description: "Toggle pretty print for the json format"}, + "use": {Description: "Set current database", subsuggestFn: c.suggestUse}, + "pretty": {Description: "Toggle pretty print for the json format"}, + "scientific": {Description: "Toggle scientific number format for the table format"}, "precision": {Description: "Specify the format of the timestamp", subsuggestFn: newSugNodeFn( "rfc3339", diff --git a/clients/v1_shell/table_model.go b/clients/v1_shell/table_model.go index 8877646..b814a29 100644 --- a/clients/v1_shell/table_model.go +++ b/clients/v1_shell/table_model.go @@ -50,40 +50,58 @@ func NewModel( curRes int, resMax int, curSer int, - serMax int) Model { + serMax int, + scientific bool) Model { cols := make([]table.Column, len(*res.Columns)+1) colWidths := make([]int, len(*res.Columns)+1) + alignment := make([]lipgloss.Position, len(*res.Columns)+1) rows := make([]table.Row, len(*res.Values)) colNames := *res.Columns for rowI, row := range *res.Values { rd := table.RowData{} rd["index"] = fmt.Sprintf("%d", rowI+1) + alignment[0] = lipgloss.Right colWidths[0] = len("index") + colPadding for colI, rowVal := range row { var item string + var colLen int switch val := rowVal.(type) { case int: item = fmt.Sprintf("%d", val) + colLen = len(item) + alignment[colI+1] = lipgloss.Right case string: - item = fmt.Sprintf("%q", val) + item = color.YellowString(val) + colLen = len(val) + alignment[colI+1] = lipgloss.Left + case float32, float64: + if scientific { + item = fmt.Sprintf("%.10e", val) + } else { + item = fmt.Sprintf("%.10f", val) + } + colLen = len(item) + alignment[colI+1] = lipgloss.Right default: item = fmt.Sprintf("%v", val) + colLen = len(item) + alignment[colI+1] = lipgloss.Right } rd[colNames[colI]] = item - if colWidths[colI+1] < len(item)+colPadding { - colWidths[colI+1] = len(item) + colPadding + if colWidths[colI+1] < colLen+colPadding { + colWidths[colI+1] = colLen + colPadding } } rows[rowI] = table.NewRow(rd). - WithStyle(lipgloss.NewStyle().Align(lipgloss.Center)) + WithStyle(lipgloss.NewStyle()) } cols[0] = table.NewColumn("index", "index", colWidths[0]) indexStyle := lipgloss.NewStyle() if isatty.IsTerminal(os.Stdout.Fd()) { indexStyle = indexStyle. Faint(true). - Align(lipgloss.Center) + Align(lipgloss.Right) } cols[0] = cols[0].WithStyle(indexStyle) for colI, colTitle := range colNames { @@ -91,7 +109,7 @@ func NewModel( colWidths[colI+1] = len(colTitle) + colPadding } cols[colI+1] = table.NewColumn(colTitle, color.HiCyanString(colTitle), colWidths[colI+1]). - WithStyle(lipgloss.NewStyle().Align(lipgloss.Center)) + WithStyle(lipgloss.NewStyle().Align(alignment[colI+1])) } colNames = append([]string{"index"}, colNames...) screenPadding := 10 @@ -122,6 +140,7 @@ func NewModel( keybind.FilterClear.Unbind() m.simpleTable = table.New(m.allCols). + HeaderStyle(lipgloss.NewStyle().Align(lipgloss.Center)). WithRows(m.rows). WithPageSize(15). WithMaxTotalWidth(500). @@ -143,7 +162,11 @@ func NewModel( func (m Model) Init() tea.Cmd { color.Magenta("Interactive Table View (press q to exit mode, shift+up/down to navigate tables):") builder := strings.Builder{} - fmt.Printf("Name: %s\n", color.GreenString(m.name)) + if m.name != "" { + fmt.Printf("Name: %s\n", color.GreenString(m.name)) + } else { + fmt.Println("") // keep a consistent height, so print an empty line + } if len(m.tags) > 0 { fmt.Print("Tags: ") for key, val := range m.tags { @@ -204,9 +227,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } else { m.simpleTable = m.simpleTable.PageDown() } - case "<": + case "[": m.simpleTable = m.simpleTable.PageFirst() - case ">": + case "]": m.simpleTable = m.simpleTable.PageLast() } case tea.WindowSizeMsg: diff --git a/clients/v1_shell/v1_shell.go b/clients/v1_shell/v1_shell.go index 51e8f25..22d8330 100644 --- a/clients/v1_shell/v1_shell.go +++ b/clients/v1_shell/v1_shell.go @@ -23,6 +23,7 @@ import ( "github.com/influxdata/go-prompt" "github.com/influxdata/influx-cli/v2/api" "github.com/influxdata/influx-cli/v2/clients" + "github.com/muesli/termenv" ) type Client struct { @@ -42,6 +43,7 @@ type PersistentQueryParams struct { Precision string Format FormatType Pretty bool + Scientific bool // Autocompletion Storage historyFilePath string historyLimit int @@ -200,6 +202,8 @@ func (c *Client) executor(cmd string) { c.settings() case "pretty": c.togglePretty() + case "scientific": + c.toggleScientific() case "use": c.use(cmdArgs) case "insert": @@ -367,9 +371,10 @@ func (c *Client) runAndShowQuery(query string) { func (c *Client) help() { fmt.Println(`Usage: - pretty toggles pretty print for the json format use sets current database format specifies the format of the server responses: json, csv, column, table + pretty toggles pretty print for the json format + scientific toggles scientific numeric format for table format precision specifies the format of the timestamp: rfc3339, h, m, s, ms, u or ns history displays command history settings outputs the current settings for the shell @@ -403,6 +408,7 @@ func (c *Client) settings() { fmt.Fprintf(w, "Database\t%s\n", c.Database) fmt.Fprintf(w, "RetentionPolicy\t%s\n", c.RetentionPolicy) fmt.Fprintf(w, "Pretty\t%v\n", c.Pretty) + fmt.Fprintf(w, "Scientific\t%v\n", c.Scientific) fmt.Fprintf(w, "Format\t%s\n", c.Format) fmt.Fprintf(w, "Precision\t%s\n", c.Precision) fmt.Fprintln(w) @@ -640,6 +646,8 @@ outer: } allSeries := res.GetSeries() for seriesIdx < len(allSeries) { + termenv.AltScreen() + defer termenv.ExitAltScreen() series := allSeries[seriesIdx] p := tea.NewProgram(NewModel(series, jumpToLastPage, @@ -648,7 +656,9 @@ outer: resIdx+1, len(allResults), seriesIdx+1, - len(allSeries))) + len(allSeries), + c.Scientific), + ) model, err := p.StartReturningModel() jumpToLastPage = false if err != nil { @@ -688,6 +698,11 @@ func (c *Client) togglePretty() { color.HiBlack("Pretty: %v", c.Pretty) } +func (c *Client) toggleScientific() { + c.Scientific = !c.Scientific + color.HiBlack("Scientific: %v", c.Scientific) +} + func (c *Client) use(args []string) { if len(args) != 2 { color.Red("wrong number of args for \"use \"") diff --git a/go.mod b/go.mod index 81f9c90..93373d2 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/influxdata/go-prompt v0.2.7 github.com/influxdata/influxdb/v2 v2.3.0 github.com/mattn/go-isatty v0.0.14 + github.com/muesli/termenv v0.12.0 github.com/olekukonko/tablewriter v0.0.5 github.com/stretchr/testify v1.7.0 github.com/urfave/cli v1.22.5 @@ -44,7 +45,6 @@ require ( github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect github.com/muesli/cancelreader v0.2.0 // indirect github.com/muesli/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.12.0 // indirect github.com/pkg/term v1.2.0-beta.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect