ui

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 6, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package ui centralizes agentsync's terminal presentation: semantic color, a curated glyph vocabulary, and small layout primitives (sections, status lines, aligned labels). It is the single place that decides whether to emit ANSI, so every command renders through a *Printer and the color/glyph/spacing language stays consistent across `status`, `diff`, `doctor`, and `apply`.

Two independent axes:

  • Color is TTY-gated. `--color=always|never` forces it; `auto` (the default) enables color only when the output is a terminal and NO_COLOR (https://no-color.org) is unset. Non-TTY output (pipes, files, tests) is therefore byte-for-byte plain — color never leaks into a redirect.
  • Glyphs are always Unicode. The ✓ / ◐ / ✗ vocabulary already appears in the translation report and the capability matrix; keeping it unconditional means piped output reads the same as the screen and existing fixtures hold. Color, not glyph choice, is what degrades.

Color is reserved for state: a green ✓ means synced, a red ✗ means drift. It is never decoration. Everything still parses with color stripped.

Index

Constants

View Source
const (
	GlyphOK      = "✓" // success / synced / clean
	GlyphPartial = "◐" // partial coverage (mirrors the capability matrix)
	GlyphErr     = "✗" // failure / drift / missing
	GlyphWarn    = "⚠" // warning / needs attention
	GlyphInfo    = "•" // neutral bullet
	GlyphArrow   = "→" // transition / "see"
)

Curated glyph vocabulary. Always Unicode; each is one display column wide, so callers can align around them with plain rune/space counting (no runewidth).

View Source
const GlyphWarnEmoji = "⚠️"

GlyphWarnEmoji is the colourful warning sign (with VS16) used as the warning label prefix. Wider than one column in some terminals, which is fine — the warning lines are not part of any padded layout.

Variables

This section is empty.

Functions

func Pad

func Pad(s string, width int) string

Pad left-justifies s to a fixed visible width, counting runes (the glyph set is single-width) rather than bytes, then returns the padded plain string. Callers color the RESULT so that ANSI bytes never throw off the column — padding is applied before any escape codes exist.

Types

type ColorMode

type ColorMode int

ColorMode is the resolved value of the global --color flag.

const (
	ColorAuto ColorMode = iota
	ColorAlways
	ColorNever
)

func ParseColorMode

func ParseColorMode(s string) (ColorMode, error)

ParseColorMode maps the --color flag string to a ColorMode. An empty string defaults to auto so callers can pass the raw flag value.

type Printer

type Printer struct {
	Out io.Writer
	Err io.Writer
	// contains filtered or unexported fields
}

Printer renders styled output to a pair of writers. Construct one per command invocation via New; the color decision is frozen at construction.

func New

func New(out, err io.Writer, mode ColorMode) *Printer

New builds a Printer bound to out/err, resolving whether to emit color from mode, the NO_COLOR environment variable, and whether out is a terminal.

func (*Printer) Blue

func (p *Printer) Blue(s string) string

func (*Printer) Bold

func (p *Printer) Bold(s string) string

Semantic style helpers. Each returns s unchanged when color is disabled, so callers can compose them freely without branching.

func (*Printer) Color

func (p *Printer) Color() bool

Color reports whether this Printer emits ANSI. Commands that hand a writer to a third-party renderer (e.g. the diff library's own colorizer) consult this to gate that output through the same decision.

func (*Printer) Cyan

func (p *Printer) Cyan(s string) string

func (*Printer) Faint

func (p *Printer) Faint(s string) string

func (*Printer) Green

func (p *Printer) Green(s string) string

func (*Printer) Red

func (p *Printer) Red(s string) string

func (*Printer) Section

func (p *Printer) Section(title string)

Section prints a heading (bold when colored, plain text otherwise) to Out.

func (*Printer) Spin

func (p *Printer) Spin(label string) func()

Spin is the one-call helper: it starts a Spinner and returns the stop function. Typical use:

stop := p.Spin("fetching marketplace github")
result, err := fetcher.Fetch(src, cacheDir)
stop()
if err != nil { ... }

func (*Printer) Spinner

func (p *Printer) Spinner(label string) *Spinner

Spinner builds a Spinner bound to p.Err and inheriting p's color decision. Call Start to begin and Stop to end; both are idempotent and safe to call in either order (a Stop without Start is a no-op).

func (*Printer) Yellow

func (p *Printer) Yellow(s string) string

type Spinner

type Spinner struct {
	// contains filtered or unexported fields
}

Spinner is a lightweight in-place progress indicator for slow network ops (marketplace fetch, plugin pull). It animates only when its writer is a terminal; off a terminal (CI logs, piped stderr, captured-output tests) it is a complete no-op — no animation, no static fallback line — so byte-stable fixtures stay byte-stable and grep'd output stays clean. The success line a caller already prints carries the result.

func (*Spinner) Start

func (s *Spinner) Start()

Start begins the animation. Idempotent; no-op on a non-terminal writer.

func (*Spinner) Stop

func (s *Spinner) Stop()

Stop ends the animation, clears the spinner line, and blocks until the animation goroutine has flushed. Idempotent; safe to call before Start (in which case it is a no-op).

type WarnWriter

type WarnWriter struct {
	// contains filtered or unexported fields
}

WarnWriter wraps a destination writer and styles "warning: " line prefixes as a bold-yellow "⚠️ warning:" so every warning — whether emitted by the CLI itself, by an adapter's Ingest, or by capture's re-reference path — reads consistently. Lines that do not start with the literal "warning: " prefix (e.g. pre-styled ANSI lines, indented continuation lines, or "agentsync:" notes) pass through verbatim. The writer is line-buffered so a callers' partial Write is held until a newline arrives — fmt.Fprintf in practice always finishes a line per call, but buffering keeps a chunked writer correct.

Not safe for concurrent use: the line-assembly buffer is unsynchronized. One *WarnWriter per command invocation is the intended pattern.

func NewWarnWriter

func NewWarnWriter(w io.Writer, p *Printer) *WarnWriter

NewWarnWriter returns a *WarnWriter that flushes styled lines to w using p. p's color decision is honored: with color off, the prefix becomes a plain "⚠️ warning:" (the glyph is content, not decoration — same rule as the curated glyph vocabulary above).

func (*WarnWriter) Flush

func (s *WarnWriter) Flush()

Flush emits any buffered partial line (no trailing \n) as-is. Call at end of command if you've routed a writer that may not always end in \n; the import path does always terminate, so this is defensive.

func (*WarnWriter) RouteTo

func (s *WarnWriter) RouteTo(a any) func()

RouteTo wires this writer into anything that exposes a SetStderr(io.Writer) setter (matching adapter.WarnEmitter) and returns a restore function that detaches the writer when invoked. Idiomatic use pairs with defer:

defer warnW.RouteTo(a)()

The inner RouteTo(a) call evaluates immediately (wires the writer); the outer () is the deferred restore. The returned function is always safe to call — it's a no-op when the target doesn't implement the setter, when the target is a typed-nil pointer, or when the target was an untyped nil — so callers never need to type-assert or nil-check.

Non-implementor cases that resolve to a silent no-op:

  • untyped nil (`any(nil)`): the type-assert misses because the interface value carries no concrete type.
  • typed nil (`var a *T = nil; RouteTo(a)`): the type-assert SUCCEEDS because the interface value holds the method set of *T, but calling SetStderr would dereference the nil pointer. RouteTo guards against this via reflect.
  • any value whose dynamic type doesn't implement SetStderr.

func (*WarnWriter) Write

func (s *WarnWriter) Write(p []byte) (int, error)

Write line-buffers data, emitting completed lines through emit. Partial trailing bytes are retained for the next Write. Always returns len(p), nil (the contract callers like fmt.Fprintf expect).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL