36b3af2e3d
PR Check / Code Quality: Format (push) Failing after 1s
PR Check / Code Quality: Lint (darwin) (push) Failing after 0s
PR Check / Code Quality: Lint (freebsd) (push) Failing after 1s
PR Check / Code Quality: Lint (windows) (push) Failing after 1s
PR Check / Code Quality: Lint (linux) (push) Failing after 1s
PR Check / Security: Vulnerability Scan (push) Failing after 0s
Update Documentation / update-docs (push) Failing after 2s
PR Check / Code Quality: Vendor (push) Failing after 1s
PR Check / Code Quality: Coverage (push) Failing after 0s
PR Check / Tests: Unit (macos-latest) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04-arm) (push) Has been cancelled
PR Check / Tests: Unit (windows-latest) (push) Has been cancelled
58 lines
1.3 KiB
Go
58 lines
1.3 KiB
Go
package output
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
type ansiString string
|
|
|
|
// Printer writes terminal-safe output to an io.Writer, sanitizing any
|
|
// string-like arguments (string, []byte, error, fmt.Stringer). Sanitization
|
|
// escapes embedded newlines/tabs so an untrusted value can't forge extra
|
|
// layout lines; the tool's own layout newlines must therefore go through
|
|
// Printf's format string (which is not sanitized), never a Print/Println arg.
|
|
type Printer struct {
|
|
w io.Writer
|
|
}
|
|
|
|
func NewPrinter(w io.Writer) Printer {
|
|
return Printer{w: w}
|
|
}
|
|
|
|
func (p Printer) Printf(format string, args ...any) {
|
|
fmt.Fprintf(p.w, format, sanitizePrintArgs(args)...)
|
|
}
|
|
|
|
func (p Printer) Print(args ...any) {
|
|
fmt.Fprint(p.w, sanitizePrintArgs(args)...)
|
|
}
|
|
|
|
func (p Printer) Println(args ...any) {
|
|
fmt.Fprintln(p.w, sanitizePrintArgs(args)...)
|
|
}
|
|
|
|
func sanitizePrintArgs(args []any) []any {
|
|
if len(args) == 0 {
|
|
return nil
|
|
}
|
|
out := make([]any, len(args))
|
|
for i, a := range args {
|
|
switch v := a.(type) {
|
|
case ansiString: // our own ansiString type is allowed to render as-is
|
|
out[i] = string(v)
|
|
case string:
|
|
out[i] = SanitizeTerminalLine(v)
|
|
case []byte:
|
|
out[i] = SanitizeTerminalLine(string(v))
|
|
case error:
|
|
out[i] = SanitizeTerminalLine(v.Error())
|
|
case fmt.Stringer:
|
|
out[i] = SanitizeTerminalLine(v.String())
|
|
default:
|
|
out[i] = a
|
|
}
|
|
}
|
|
return out
|
|
}
|