// Copyright (c) 2026, Pim van Pelt package main import "strings" const ( ansiBlue = "\x1b[34m" ansiRed = "\x1b[31m" ansiReset = "\x1b[0m" ) // colorEnabled is set by the -color flag in main. var colorEnabled bool // label wraps s in dark-blue ANSI when color output is enabled. // // Tabwriter caveat: tabwriter.Writer counts *bytes* per cell, not // rendered columns. ANSI escape codes (`\x1b[34m…\x1b[0m`, 11 bytes) // inflate a cell's apparent width without affecting what the terminal // draws. Two things follow: // // 1. Key-value layouts where column 1 is *always* labelled and // column 2 is *always* plain (e.g. `show vpp info`) stay aligned, // because every row adds the same 11 bytes to column 1. // 2. Multi-column tables where only the *header* row is labelled // drift: the header cells each carry 11 extra bytes that the data // rows don't, so data cells get over-padded. In those tables, // leave the header plain (see runShowVPPLBCounters) and only use // label() for labels that appear uniformly column-wise. func label(s string) string { if !colorEnabled { return s } return ansiBlue + s + ansiReset } // formatError returns a user-friendly error string. gRPC status errors are // unwrapped to show only the server's message (no "rpc error: code = ..." // boilerplate). The result is wrapped in red ANSI when color is enabled. func formatError(err error) string { msg := err.Error() // google.golang.org/grpc/status errors format as: // rpc error: code = desc = if i := strings.Index(msg, " desc = "); i >= 0 { msg = msg[i+len(" desc = "):] } if colorEnabled { return ansiRed + msg + ansiReset } return msg }