Documentation
¶
Overview ¶
Package formatting provides product-agnostic table view policies on top of the framework output primitives.
Index ¶
- Variables
- func DefaultProcessor() *frameworkoutput.Processor
- func Normalize(data any) any
- func RenderCell(v any, maxWidth int) string
- func ResolveColumns(row map[string]any, selected []string, maxCols int, priority []string) []string
- func TruncateBalanced(s string, maxWidth int) string
- func UnwrapWrapperObject(data any) any
- type CompositeFormatter
- type DataShape
- type TableView
- type ViewRegistry
Constants ¶
This section is empty.
Variables ¶
var GlobalColumnPriority = []string{
"id", "key", "work_item_id", "work_item_type_key",
"name", "title", "subject", "display_name",
"state", "status", "state_key",
"owner", "assignee", "created_by", "user_key",
"email",
"created_at", "updated_at", "finish_time",
}
GlobalColumnPriority is the seed priority list for auto-column-selection when the user does not pass --select. Hits come first in priority order; remaining keys are appended alphabetically up to the column cap.
Functions ¶
func DefaultProcessor ¶
func DefaultProcessor() *frameworkoutput.Processor
DefaultProcessor assembles the full output pipeline for a product: select → envelope → composite formatter (json/ndjson/table) → stdio writer. Products should use this instead of pkg/framework/output/formatter.DefaultProcessor() when they want table rendering.
No implicit wrapper-array unwrap happens in the hook chain — every format receives the raw response so metadata siblings (total, pagination, ...) are preserved. Users drill into wrapped records explicitly via --select=KEY or --select=KEY.field, where the FieldSelectorHook broadcasts the remaining path over array elements when needed. CompositeFormatter still applies a loss-less single-key peel before table/ndjson rendering so {"list":[...]} alone still renders as rows.
func RenderCell ¶
RenderCell returns the table-cell string for an arbitrary value.
Rules (matching the design spec §格式行为规约 > table):
- nil → ""
- string/number/bool → Sprint, truncated by maxWidth
- primitive-only arrays → comma-joined, truncated
- objects and mixed/object arrays → compact JSON, bracket-balanced truncation
maxWidth <= 0 disables truncation.
func ResolveColumns ¶
ResolveColumns picks the final column order for a row.
- If selected is non-empty, that list is used verbatim (honoring user intent).
- Otherwise: priority hits (in priority order) come first; remaining keys are appended in alphabetical order. Result is capped at maxCols.
func TruncateBalanced ¶
TruncateBalanced shortens a rendered string to at most maxWidth runes.
- Strings not starting with '{' or '[' are tail-truncated with '…'.
- Objects/arrays are truncated between top-level items when possible: the result stays a well-formed JSON literal whose final character is the closing bracket, with a trailing ",…]" / ",…}" to flag truncation.
- If even one top-level item does not fit within budget (e.g. a single long object inside a cell narrower than the object), we fall back to plain tail-truncation so the user still sees content. That violates the "always valid JSON" guarantee but is preferable to emitting a deceptively empty "[]" or "{}".
maxWidth <= 0 or short input → returned unchanged.
func UnwrapWrapperObject ¶
UnwrapWrapperObject performs loss-less drill-in before table/ndjson rendering so that single-wrapper payloads render naturally:
- Single-key map whose value is []any → returns the []any (e.g. {"list":[...]} → [...]).
- Single-key map whose value is a map[string]any → returns the inner map, and repeats (e.g. {"creator":{"name":"alice","email":"x"}} → {"name":"alice","email":"x"}).
Peeling is strictly loss-less: it stops as soon as the current map has zero or more than one key, so {"list":[...], "total":N} is never peeled — metadata siblings are preserved and the renderer shows the outer KV/structure. Scalar values under a single key are also left alone so {"creator":"alice"} stays a KV row instead of collapsing into "alice".
Types ¶
type CompositeFormatter ¶
type CompositeFormatter struct {
Base frameworkoutput.Formatter
Table TableView
}
CompositeFormatter dispatches by FormatOptions.Mode:
- "table" → TableView.Encode (after wrapper-array unwrap)
- "ndjson" → Base.Format (after wrapper-array unwrap)
- "json" / "" → Base.Format (pass-through, no unwrap)
- anything else → user-facing error listing the supported set
Unwrap rationale: most MCP list responses arrive as {"list": [...]} / {"data": [...]} wrappers. For ndjson and table the wrapper hides the records users want to stream/tabulate, so we peel it; json stays faithful so existing scripts reading .list[0] keep working. When --envelope is on, we do NOT unwrap (the envelope itself is a {data, meta, error} wrapper and that is exactly what the user asked to see).
Error-envelope rendering (FormatOptions.ErrorEnvelope=true) takes priority over everything above: no unwrapping, and table mode renders the inner `error` record as a KV table with code/message/retryable rows per the design spec §"错误处理契约".
func NewComposite ¶
func NewComposite(base frameworkoutput.Formatter, table TableView) CompositeFormatter
NewComposite wires a base framework Formatter and a TableView into a single Formatter usable by frameworkoutput.Processor.
func (CompositeFormatter) Format ¶
func (c CompositeFormatter) Format(data any, opts *frameworkoutput.FormatOptions) ([]byte, error)
type DataShape ¶
type DataShape int
DataShape classifies an arbitrary payload for table rendering.
func DetectShape ¶
DetectShape inspects data and returns its shape. Inputs wrapped as json.RawMessage or []byte are decoded first.
type TableView ¶
type TableView struct {
ColumnPriority []string
MaxColumns int // default 8; --verbose bumps to 16
MaxCellWidth int // default 40
Stderr io.Writer // hints target; defaults to os.Stderr
}
TableView is the table-mode Formatter. It is shape-aware and produces deterministic output even when the input payload is irregular.
func DefaultTableView ¶
func DefaultTableView() TableView
DefaultTableView returns a TableView with the standard policies.
func (TableView) Encode ¶
func (v TableView) Encode(data any, opts *frameworkoutput.FormatOptions) ([]byte, error)
Encode renders data as an ASCII table according to the shape-aware rules.
type ViewRegistry ¶
type ViewRegistry struct{}
ViewRegistry is a placeholder extension point for per-command column overrides. The current design commits to the global priority list covering ~80% of commands (see spec §决策摘要); add RegisterView methods here when a command needs a bespoke view. Keeping this type published ensures the API shape is stable before the first override lands.
func NewViewRegistry ¶
func NewViewRegistry() *ViewRegistry
NewViewRegistry returns a new empty registry.