Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

76 lines
2.1 KiB
Go

package progress
import (
"io"
"os"
"sync/atomic"
"golang.org/x/term"
)
// IsTTY reports whether w is backed by a terminal file descriptor.
func IsTTY(w io.Writer) bool {
f, ok := w.(interface{ Fd() uintptr })
if !ok {
return false
}
return term.IsTerminal(int(f.Fd()))
}
func envDisablesColor() bool {
if os.Getenv("NO_COLOR") != "" {
return true
}
if t := os.Getenv("TERM"); t == "dumb" {
return true
}
return false
}
// animationAllowed decides whether w can host the animated renderer. The
// contract matches the --no-progress help text: NO_COLOR, TERM=dumb, a
// non-TTY writer, and CI all force plain output. On Windows it additionally
// requires the console to accept VT processing (legacy conhost without VT
// gets plain text rather than raw escape soup). GORTEX_FORCE_ANIMATION=1
// overrides everything — it exists for demos and PTY-less frame capture.
func animationAllowed(w io.Writer) bool {
if envFlag("GORTEX_FORCE_ANIMATION") {
return true
}
if !IsTTY(w) {
return false
}
if envDisablesColor() {
return false
}
if os.Getenv("CI") != "" {
return false
}
return enableVT(w)
}
// cursorHiddenOnStderr tracks whether an animated tracker writing to the
// process stderr currently has the cursor hidden. RestoreTerminal uses it to
// undo the hide from exit paths that bypass a tracker's own finish (fatal
// errors, panics unwinding main).
var cursorHiddenOnStderr atomic.Bool
// RestoreTerminal re-shows the cursor and resets SGR state on stderr if an
// animated tracker left the cursor hidden. Safe to call unconditionally and
// repeatedly; a no-op when nothing needs restoring. Wire it into every
// process exit path that can interrupt a live animation.
func RestoreTerminal() {
if cursorHiddenOnStderr.CompareAndSwap(true, false) {
_, _ = os.Stderr.WriteString(ansiShowCursor + ansiReset)
}
}
func markCursorHidden(w io.Writer) { setCursorFlag(w, true) }
func markCursorRestored(w io.Writer) { setCursorFlag(w, false) }
func setCursorFlag(w io.Writer, hidden bool) {
if f, ok := w.(*os.File); ok && f == os.Stderr {
cursorHiddenOnStderr.Store(hidden)
}
}