feat: add pretty table format to REPL (#393)
* add v1-compatible query path and refactor other paths to de-duplicate "/query" * add initial influxQL repl * add ping endpoint to schema * improve prompt UX, implement some commands * fix json column type in schema and improve completion * feat: add table formatter and move to forked go-prompt * improve formatting and add table pagination * implement more REPL commands, including insert and history * implement "INSERT INTO" * move repl command to "v1 repl" * refactor and improve documentation * clean up v1_repl cmd * update to latest openapi, use some openapi paths instead of overrides * remove additional files that were moved to openapi * compute historyFilePath at REPL start * clean up REPL use command logic flow * clean up comments for TODOs now in issues * move gopher (chonky boi) * remove autocompletion for separate PR * run go mod tidy * add rfc3339 precision option * allow left and right column scrolling to display whole table * add error to JSON query response * add tags and partial to JSON response series schema * fix csv formatting and add column formatting * remove table format for separate PR * add pretty table format to REPL * fix getDatabases * move from write to legacy write endpoint for INSERT * remove history vestiges * allow multiple spaces in INSERT commands * add precision comment * remove auth for separate PR * separate parseInsert and add unit test * add additional test case and improve error messages * fix missing errors import * update for simpler horizontal scrolling in table mode * improve dialog printing * improve table format and interactions * jump to first page on shift-up * add keybinding info * change wording from result to table, flip
This commit is contained in:
parent
85c690f1f1
commit
9dc1b8e4b1
@ -148,6 +148,7 @@ func (c *Client) completer(d prompt.Document) []prompt.Suggest {
|
||||
"column",
|
||||
"csv",
|
||||
"json",
|
||||
"table",
|
||||
)},
|
||||
"SELECT": {subsuggestFn: c.suggestSelect},
|
||||
"INSERT": {},
|
||||
|
231
clients/v1_shell/table_model.go
Normal file
231
clients/v1_shell/table_model.go
Normal file
@ -0,0 +1,231 @@
|
||||
package v1shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/evertras/bubble-table/table"
|
||||
"github.com/fatih/color"
|
||||
"github.com/influxdata/influx-cli/v2/api"
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
const (
|
||||
colPadding int = 2
|
||||
)
|
||||
|
||||
type EndingStatus uint
|
||||
|
||||
const (
|
||||
quitStatus EndingStatus = iota
|
||||
goToPrevTableStatus
|
||||
goToPrevTableJumpFirstPageStatus
|
||||
goToNextTableStatus
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
name string
|
||||
tags map[string]string
|
||||
curResult int
|
||||
resultMax int
|
||||
curSeries int
|
||||
seriesMax int
|
||||
rows []table.Row
|
||||
allCols []table.Column
|
||||
colNames []string
|
||||
simpleTable table.Model
|
||||
totalWidth int
|
||||
endingStatus EndingStatus
|
||||
tableScreenPadding int
|
||||
}
|
||||
|
||||
func NewModel(
|
||||
res api.InfluxqlJsonResponseSeries,
|
||||
jumpToFirstPage bool,
|
||||
name string,
|
||||
tags map[string]string,
|
||||
curRes int,
|
||||
resMax int,
|
||||
curSer int,
|
||||
serMax int) Model {
|
||||
|
||||
cols := make([]table.Column, len(*res.Columns)+1)
|
||||
colWidths := make([]int, 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)
|
||||
colWidths[0] = len("index") + colPadding
|
||||
for colI, rowVal := range row {
|
||||
var item string
|
||||
switch val := rowVal.(type) {
|
||||
case int:
|
||||
item = fmt.Sprintf("%d", val)
|
||||
case string:
|
||||
item = fmt.Sprintf("%q", val)
|
||||
default:
|
||||
item = fmt.Sprintf("%v", val)
|
||||
}
|
||||
rd[colNames[colI]] = item
|
||||
if colWidths[colI+1] < len(item)+colPadding {
|
||||
colWidths[colI+1] = len(item) + colPadding
|
||||
}
|
||||
}
|
||||
rows[rowI] = table.NewRow(rd).
|
||||
WithStyle(lipgloss.NewStyle().Align(lipgloss.Center))
|
||||
}
|
||||
cols[0] = table.NewColumn("index", "index", colWidths[0])
|
||||
indexStyle := lipgloss.NewStyle()
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
indexStyle = indexStyle.
|
||||
Faint(true).
|
||||
Align(lipgloss.Center)
|
||||
}
|
||||
cols[0] = cols[0].WithStyle(indexStyle)
|
||||
for colI, colTitle := range colNames {
|
||||
if colWidths[colI+1] < len(colTitle)+colPadding {
|
||||
colWidths[colI+1] = len(colTitle) + colPadding
|
||||
}
|
||||
cols[colI+1] = table.NewColumn(colTitle, color.HiCyanString(colTitle), colWidths[colI+1]).
|
||||
WithStyle(lipgloss.NewStyle().Align(lipgloss.Center))
|
||||
}
|
||||
colNames = append([]string{"index"}, colNames...)
|
||||
screenPadding := 10
|
||||
if len(tags) > 0 {
|
||||
screenPadding++
|
||||
}
|
||||
m := Model{
|
||||
name: name,
|
||||
tags: tags,
|
||||
curResult: curRes,
|
||||
resultMax: resMax,
|
||||
curSeries: curSer,
|
||||
seriesMax: serMax,
|
||||
rows: rows,
|
||||
allCols: cols,
|
||||
colNames: colNames,
|
||||
tableScreenPadding: screenPadding,
|
||||
}
|
||||
keybind := table.DefaultKeyMap()
|
||||
keybind.RowUp.SetEnabled(false)
|
||||
keybind.RowDown.SetEnabled(false)
|
||||
keybind.PageUp.SetEnabled(false)
|
||||
keybind.PageDown.SetEnabled(false)
|
||||
keybind.ScrollLeft.SetKeys("left")
|
||||
keybind.ScrollRight.SetKeys("right")
|
||||
keybind.Filter.Unbind()
|
||||
keybind.FilterBlur.Unbind()
|
||||
keybind.FilterClear.Unbind()
|
||||
|
||||
m.simpleTable = table.New(m.allCols).
|
||||
WithRows(m.rows).
|
||||
WithPageSize(15).
|
||||
WithMaxTotalWidth(500).
|
||||
WithHorizontalFreezeColumnCount(1).
|
||||
WithStaticFooter(
|
||||
fmt.Sprintf("%d Columns, %d Rows, Page %d/%d",
|
||||
len(m.allCols), len(m.rows), m.simpleTable.CurrentPage(), m.simpleTable.MaxPages())).
|
||||
HighlightStyle(lipgloss.NewStyle()).
|
||||
Focused(true).
|
||||
SelectableRows(false).
|
||||
WithKeyMap(keybind)
|
||||
|
||||
if jumpToFirstPage {
|
||||
m.simpleTable = m.simpleTable.PageLast()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
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 len(m.tags) > 0 {
|
||||
fmt.Print("Tags: ")
|
||||
for key, val := range m.tags {
|
||||
if key == "" || val == "" {
|
||||
continue
|
||||
}
|
||||
builder.WriteString(fmt.Sprintf("%s=%s, ", color.YellowString(key), color.CyanString(val)))
|
||||
}
|
||||
tagline := builder.String()
|
||||
fmt.Print(tagline[:len(tagline)-2])
|
||||
fmt.Println("")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var (
|
||||
cmd tea.Cmd
|
||||
cmds []tea.Cmd
|
||||
)
|
||||
|
||||
m.simpleTable, cmd = m.simpleTable.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "ctrl+d", "esc", "q":
|
||||
m.simpleTable = m.simpleTable.Focused(false)
|
||||
fmt.Printf("\n")
|
||||
m.endingStatus = quitStatus
|
||||
cmds = append(cmds, tea.Quit)
|
||||
case "shift+up":
|
||||
if !(m.curResult == 1 && m.curSeries == 1) {
|
||||
m.endingStatus = goToPrevTableJumpFirstPageStatus
|
||||
cmds = append(cmds, tea.Quit)
|
||||
}
|
||||
case "shift+down":
|
||||
if !(m.curResult == m.resultMax && m.curSeries == m.seriesMax) {
|
||||
m.endingStatus = goToNextTableStatus
|
||||
cmds = append(cmds, tea.Quit)
|
||||
}
|
||||
case "up":
|
||||
if m.simpleTable.CurrentPage() == 1 {
|
||||
if !(m.curResult == 1 && m.curSeries == 1) {
|
||||
m.endingStatus = goToPrevTableStatus
|
||||
cmds = append(cmds, tea.Quit)
|
||||
}
|
||||
} else {
|
||||
m.simpleTable = m.simpleTable.PageUp()
|
||||
}
|
||||
case "down":
|
||||
if m.simpleTable.CurrentPage() == m.simpleTable.MaxPages() {
|
||||
if !(m.curResult == m.resultMax && m.curSeries == m.seriesMax) {
|
||||
m.endingStatus = goToNextTableStatus
|
||||
cmds = append(cmds, tea.Quit)
|
||||
}
|
||||
} else {
|
||||
m.simpleTable = m.simpleTable.PageDown()
|
||||
}
|
||||
case "<":
|
||||
m.simpleTable = m.simpleTable.PageFirst()
|
||||
case ">":
|
||||
m.simpleTable = m.simpleTable.PageLast()
|
||||
}
|
||||
case tea.WindowSizeMsg:
|
||||
m.totalWidth = msg.Width
|
||||
m.simpleTable = m.simpleTable.WithPageSize(msg.Height - m.tableScreenPadding).
|
||||
WithMaxTotalWidth(msg.Width)
|
||||
}
|
||||
m.simpleTable = m.simpleTable.WithStaticFooter(
|
||||
fmt.Sprintf("%d Columns, %d Rows, Page %d/%d\nTable %d/%d, Statement %d/%d",
|
||||
len(m.allCols), len(m.rows), m.simpleTable.CurrentPage(), m.simpleTable.MaxPages(),
|
||||
m.curSeries, m.seriesMax,
|
||||
m.curResult, m.resultMax))
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
func (m Model) View() string {
|
||||
body := strings.Builder{}
|
||||
|
||||
body.WriteString(m.simpleTable.View())
|
||||
body.WriteString("\n")
|
||||
return body.String()
|
||||
}
|
@ -18,6 +18,7 @@ import (
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/fatih/color"
|
||||
"github.com/influxdata/go-prompt"
|
||||
"github.com/influxdata/influx-cli/v2/api"
|
||||
@ -51,7 +52,7 @@ type PersistentQueryParams struct {
|
||||
|
||||
func DefaultPersistentQueryParams() PersistentQueryParams {
|
||||
return PersistentQueryParams{
|
||||
Format: ColumnFormat,
|
||||
Format: TableFormat,
|
||||
Precision: "ns",
|
||||
historyLimit: 1000,
|
||||
}
|
||||
@ -89,7 +90,7 @@ func (c *Client) rewriteHistoryFile(history []string) {
|
||||
func (c *Client) writeCommandToHistory(cmd string) {
|
||||
if c.historyFilePath != "" {
|
||||
if historyFile, err := os.OpenFile(c.historyFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666); err == nil {
|
||||
historyFile.WriteString(cmd + "\n")
|
||||
historyFile.WriteString(strings.TrimSpace(cmd) + "\n")
|
||||
historyFile.Close()
|
||||
}
|
||||
}
|
||||
@ -326,6 +327,7 @@ var (
|
||||
CsvFormat FormatType = "csv"
|
||||
JsonFormat FormatType = "json"
|
||||
ColumnFormat FormatType = "column"
|
||||
TableFormat FormatType = "table"
|
||||
)
|
||||
|
||||
func (c *Client) runAndShowQuery(query string) {
|
||||
@ -357,6 +359,7 @@ func (c *Client) runAndShowQuery(query string) {
|
||||
CsvFormat: c.outputCsv,
|
||||
JsonFormat: c.outputJson,
|
||||
ColumnFormat: c.outputColumns,
|
||||
TableFormat: c.outputTable,
|
||||
}
|
||||
displayFunc := displayMap[c.Format]
|
||||
displayFunc(response)
|
||||
@ -366,7 +369,7 @@ func (c *Client) help() {
|
||||
fmt.Println(`Usage:
|
||||
pretty toggles pretty print for the json format
|
||||
use <db_name> sets current database
|
||||
format <format> specifies the format of the server responses: json, csv, column
|
||||
format <format> specifies the format of the server responses: json, csv, column, table
|
||||
precision <format> 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
|
||||
@ -387,7 +390,9 @@ func (c *Client) help() {
|
||||
<CTRL+D> exit
|
||||
<CTRL+L> clear screen
|
||||
<UP ARROW> previous command
|
||||
<DOWN ARROW> next command`)
|
||||
<DOWN ARROW> next command
|
||||
<TAB> next suggestion
|
||||
<SHIFT+TAB> previous suggestion`)
|
||||
}
|
||||
|
||||
func (c *Client) settings() {
|
||||
@ -424,16 +429,16 @@ func (c *Client) query(ctx context.Context, query string) (string, error) {
|
||||
func (c *Client) setFormat(args []string) {
|
||||
// args[0] is "format"
|
||||
if len(args) != 2 {
|
||||
color.Red("Expected a format [csv, json, column]")
|
||||
color.Red("Expected a format [csv, json, column, table]")
|
||||
return
|
||||
}
|
||||
newFormat := FormatType(args[1])
|
||||
switch newFormat {
|
||||
case CsvFormat, JsonFormat, ColumnFormat:
|
||||
case CsvFormat, JsonFormat, ColumnFormat, TableFormat:
|
||||
c.Format = newFormat
|
||||
default:
|
||||
color.HiRed("Unimplemented format %q, keeping %s format.", newFormat, c.Format)
|
||||
color.HiBlack("Choose a format from [csv, json, column]")
|
||||
color.HiBlack("Choose a format from [csv, json, column, table]")
|
||||
}
|
||||
}
|
||||
|
||||
@ -556,7 +561,7 @@ func (c *Client) outputCsv(response api.InfluxqlJsonResponse) {
|
||||
var previousHeaders api.InfluxqlJsonResponseSeries
|
||||
for _, result := range response.GetResults() {
|
||||
if result.Error != nil {
|
||||
color.Red("Query Error: %v", result.GetError())
|
||||
color.Red("Error: %v", result.GetError())
|
||||
continue
|
||||
}
|
||||
series := result.GetSeries()
|
||||
@ -596,7 +601,7 @@ func (c *Client) outputColumns(response api.InfluxqlJsonResponse) {
|
||||
var previousHeaders api.InfluxqlJsonResponseSeries
|
||||
for i, result := range response.GetResults() {
|
||||
if result.Error != nil {
|
||||
color.Red("Query Error: %v", result.GetError())
|
||||
color.Red("Error: %v", result.GetError())
|
||||
continue
|
||||
}
|
||||
|
||||
@ -621,6 +626,63 @@ func (c *Client) outputColumns(response api.InfluxqlJsonResponse) {
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
func (c *Client) outputTable(response api.InfluxqlJsonResponse) {
|
||||
allResults := response.GetResults()
|
||||
resIdx := 0
|
||||
seriesIdx := 0
|
||||
jumpToLastPage := false
|
||||
outer:
|
||||
for resIdx < len(allResults) {
|
||||
res := allResults[resIdx]
|
||||
if res.Error != nil {
|
||||
color.Red("Error: %v", res.GetError())
|
||||
resIdx++
|
||||
}
|
||||
allSeries := res.GetSeries()
|
||||
for seriesIdx < len(allSeries) {
|
||||
series := allSeries[seriesIdx]
|
||||
p := tea.NewProgram(NewModel(series,
|
||||
jumpToLastPage,
|
||||
series.GetName(),
|
||||
series.GetTags(),
|
||||
resIdx+1,
|
||||
len(allResults),
|
||||
seriesIdx+1,
|
||||
len(allSeries)))
|
||||
model, err := p.StartReturningModel()
|
||||
jumpToLastPage = false
|
||||
if err != nil {
|
||||
color.Red("Failed to display table")
|
||||
seriesIdx++
|
||||
} else {
|
||||
if tableModel, ok := model.(Model); ok {
|
||||
switch tableModel.endingStatus {
|
||||
case goToNextTableStatus:
|
||||
seriesIdx++
|
||||
case goToPrevTableStatus:
|
||||
jumpToLastPage = true
|
||||
seriesIdx--
|
||||
case goToPrevTableJumpFirstPageStatus:
|
||||
seriesIdx--
|
||||
case quitStatus:
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
if seriesIdx >= len(allSeries) {
|
||||
resIdx++
|
||||
seriesIdx = 0
|
||||
break
|
||||
} else if seriesIdx < 0 {
|
||||
resIdx--
|
||||
seriesIdx = len(allResults[resIdx].GetSeries()) - 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) togglePretty() {
|
||||
c.Pretty = !c.Pretty
|
||||
color.HiBlack("Pretty: %v", c.Pretty)
|
||||
|
13
go.mod
13
go.mod
@ -6,7 +6,10 @@ require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.4
|
||||
github.com/BurntSushi/toml v0.4.1
|
||||
github.com/MakeNowJust/heredoc/v2 v2.0.1
|
||||
github.com/charmbracelet/bubbletea v0.21.0
|
||||
github.com/charmbracelet/lipgloss v0.5.0
|
||||
github.com/daixiang0/gci v0.2.8
|
||||
github.com/evertras/bubble-table v0.13.7
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/fujiwara/shapeio v1.0.0
|
||||
github.com/gocarina/gocsv v0.0.0-20210408192840-02d7211d929d
|
||||
@ -26,13 +29,21 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
github.com/charmbracelet/bubbles v0.11.0 // indirect
|
||||
github.com/containerd/console v1.0.3 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-tty v0.0.4 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
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
|
||||
@ -42,7 +53,7 @@ require (
|
||||
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
)
|
||||
|
41
go.sum
41
go.sum
@ -7,6 +7,17 @@ github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZ
|
||||
github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/charmbracelet/bubbles v0.11.0 h1:fBLyY0PvJnd56Vlu5L84JJH6f4axhgIJ9P3NET78f0Q=
|
||||
github.com/charmbracelet/bubbles v0.11.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc=
|
||||
github.com/charmbracelet/bubbletea v0.21.0 h1:f3y+kanzgev5PA916qxmDybSHU3N804uOnKnhRPXTcI=
|
||||
github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/lipgloss v0.5.0 h1:lulQHuVeodSgDez+3rGiuxlPVXSnhth442DATR2/8t8=
|
||||
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
|
||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
|
||||
@ -18,6 +29,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/evertras/bubble-table v0.13.7 h1:XFwiax3ZEOG8P0qlZE3vgXsfYMJNunz5M4pZg4YPJU4=
|
||||
github.com/evertras/bubble-table v0.13.7/go.mod h1:SPOZKbIpyYWPHBNki3fyNpiPBQkvkULAtOT7NTD5fKY=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fujiwara/shapeio v1.0.0 h1:xG5D9oNqCSUUbryZ/jQV3cqe1v2suEjwPIcEg1gKM8M=
|
||||
@ -42,6 +55,9 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
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-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
@ -53,22 +69,38 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA=
|
||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
||||
github.com/muesli/cancelreader v0.2.0 h1:SOpr+CfyVNce341kKqvbhhzQhBPyJRXQaCtn03Pae1Q=
|
||||
github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||
github.com/muesli/termenv v0.12.0 h1:KuQRUE3PgxRFWhq4gHvZtPSLCGDqM5q/cYr1pZ39ytc=
|
||||
github.com/muesli/termenv v0.12.0/go.mod h1:WCCv32tusQ/EEZ5S8oUIIrC/nIuBcxCVqlN4Xfkv+7A=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw=
|
||||
github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
@ -107,13 +139,18 @@ golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8=
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
|
Loading…
x
Reference in New Issue
Block a user