package iostreams import ( "fmt" "strings" "text/tabwriter" ) // TablePrinter prints TTY-aware tables. In TTY mode it uses aligned columns with // bold headers. In pipe mode it emits tab-separated values without headers. type TablePrinter struct { ios *IOStreams headers []string rows [][]string } // NewTablePrinter creates a TablePrinter that writes to ios.Out. func NewTablePrinter(ios *IOStreams) *TablePrinter { return &TablePrinter{ ios: ios, } } // AddHeader sets the column headers. Headers are only displayed in TTY mode. func (t *TablePrinter) AddHeader(headers ...string) { t.headers = headers } // AddRow appends a row of fields to the table. func (t *TablePrinter) AddRow(fields ...string) { t.rows = append(t.rows, fields) } // Render writes the table to the IOStreams output. In TTY mode it uses tabwriter // with bold headers. In pipe mode it emits tab-separated values without headers. func (t *TablePrinter) Render() error { if !t.ios.IsStdoutTTY() { // Pipe mode: tab-separated, no headers for _, row := range t.rows { if _, err := fmt.Fprintln(t.ios.Out, strings.Join(row, "\t")); err != nil { return err } } return nil } // TTY mode: use tabwriter with aligned columns w := tabwriter.NewWriter(t.ios.Out, 0, 0, 2, ' ', 0) if len(t.headers) > 0 { cs := t.ios.ColorScheme() boldHeaders := make([]string, len(t.headers)) for i, h := range t.headers { boldHeaders[i] = cs.Bold(h) } fmt.Fprintln(w, strings.Join(boldHeaders, "\t")) } for _, row := range t.rows { fmt.Fprintln(w, strings.Join(row, "\t")) } return w.Flush() }