filters

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package filters compresses shell-command output before it reaches the model, RTK-style: an ordered set of command-aware semantic filters over a universal fallback. Every filter is pure (no I/O, no shared state), so the whole pipeline is safe to run concurrently from each bash call.

Index

Constants

View Source
const MaxLines = 1000

MaxLines caps universal (post-filter) output middle-out. Semantic filters do the heavy compression; this is only the safety net for commands with no dedicated filter, so it stays generous — the point is to bound pathological output, not to drop signal.

Variables

This section is empty.

Functions

func Apply

func Apply(command, raw string, exit int) (filtered string, saved int)

Apply routes raw output through the matching semantic filter (if any), then the universal fallback pipeline: trailing-space trim, blank squeeze, edge trim, middle-out cap. Commands with no dedicated filter additionally get consecutive-run dedup — a semantic filter's output is left un-deduped because those formats carry meaningful repeats. saved is estimated at bytes/4 against the untouched input, matching the ledger's convention elsewhere.

func BaseCommand

func BaseCommand(command string) []string

BaseCommand tokenizes the final segment of a possibly-chained shell command, skipping leading environment assignments (FOO=1 BAR=baz cmd …). It is the single source of truth for command identification: both the filter registry and the savings ledger (via ExtractBaseCommand) parse commands through here so their keys always agree.

func CapLines

func CapLines(lines []string) []string

CapLines truncates middle-out to MaxLines, leaving a marker naming how many lines were dropped. Head and tail are kept because that is where a command's setup and verdict live.

func DedupConsecutive

func DedupConsecutive(lines []string) []string

DedupConsecutive collapses runs of identical lines into one line tagged with a `(×N)` multiplier. Only applied to the universal fallback — semantic-filter output carries meaningful repeats and is left alone.

func JoinLines

func JoinLines(lines []string, endedNL bool) string

JoinLines rejoins lines with newlines, restoring a trailing newline when the original output had one.

func SplitLines

func SplitLines(s string) []string

SplitLines splits on newlines without allocating a final empty element for a trailing newline — callers re-add the terminator via JoinLines.

func SqueezeBlanks

func SqueezeBlanks(lines []string) []string

SqueezeBlanks collapses runs of blank lines into a single blank line.

func StripANSI

func StripANSI(s string) string

StripANSI removes CSI escape sequences (colors, cursor moves). It is the first thing every filter sees, so downstream matching is on plain text.

func TrimBlankEdges

func TrimBlankEdges(lines []string) []string

TrimBlankEdges drops leading and trailing blank lines.

func TrimTrailingSpace

func TrimTrailingSpace(lines []string) []string

TrimTrailingSpace strips trailing spaces/tabs/CR from every line.

Types

type Filter

type Filter interface {
	// Name identifies the filter in diagnostics; it is also the shape of
	// the savings-ledger key for commands this filter claims.
	Name() string
	// Match reports whether this filter handles the command whose parsed
	// fields these are — env assignments already stripped, fields[0] the
	// program (path base not yet stripped; use the progOf helper).
	Match(fields []string) bool
	// Filter rewrites raw (ANSI already stripped) into compact form. exit
	// is the process exit code and steers verbosity: 0 may collapse hard to
	// a summary; nonzero must preserve failure detail; an unmodeled nonzero
	// should return raw untouched so a real failure is never hidden.
	Filter(fields []string, raw string, exit int) string
}

Filter is a command-aware output compressor.

type GitFilter

type GitFilter struct{}

GitFilter compresses git's human output into compact one-line-per-item form: status becomes porcelain-style letters under a branch header, log collapses to short-hash + subject, a large diff/show becomes per-file insertion/deletion stats, and transport commands drop remote chatter. Any output that does not match the expected shape is returned unchanged — a filter must never destroy output it does not understand.

func (GitFilter) Filter

func (GitFilter) Filter(fields []string, raw string, exit int) string

func (GitFilter) Match

func (GitFilter) Match(fields []string) bool

func (GitFilter) Name

func (GitFilter) Name() string

type GoFilter

type GoFilter struct{}

GoFilter handles the `go` toolchain. `go test` gets the full treatment: a `-json` event stream is aggregated into a per-package pass/fail/skip summary with failing-test output kept verbatim, and human text mode drops the RUN/PASS chatter while keeping ok/FAIL lines. It handles only `go test`; the other `go` subcommands are declarative rules (rules.go: go build/vet → pass/fail, go mod/get → download strip, go run → passthrough), so subcommand behavior lives in one place.

func (GoFilter) Filter

func (GoFilter) Filter(fields []string, raw string, exit int) string

func (GoFilter) Match

func (GoFilter) Match(fields []string) bool

func (GoFilter) Name

func (GoFilter) Name() string

type InstallFilter

type InstallFilter struct{}

InstallFilter strips the noise from JavaScript package-manager installs (npm, yarn, pnpm, bun): deprecation warnings, funding/audit footers, and progress lines. The final "added N packages" style result line is kept. A failed install keeps everything, since the error text is what matters.

func (InstallFilter) Filter

func (InstallFilter) Filter(fields []string, raw string, exit int) string

func (InstallFilter) Match

func (InstallFilter) Match(fields []string) bool

func (InstallFilter) Name

func (InstallFilter) Name() string

type OutputMatch

type OutputMatch struct {
	Pattern *regexp.Regexp
	Message string
}

OutputMatch is a whole-output success detector.

type PytestFilter

type PytestFilter struct{}

PytestFilter compresses pytest runs. On a clean run it collapses to the final summary line ("=== 42 passed in 1.2s ==="), dropping the platform banner and the per-file progress dots. On a failing run it keeps the FAILURES/ERRORS section onward — the tracebacks, the short test summary, and the final line — while dropping the noisy preamble. Anything it does not recognize is returned untouched.

func (PytestFilter) Filter

func (PytestFilter) Filter(fields []string, raw string, exit int) string

func (PytestFilter) Match

func (PytestFilter) Match(fields []string) bool

func (PytestFilter) Name

func (PytestFilter) Name() string

type Replacement

type Replacement struct {
	Pattern *regexp.Regexp
	Repl    string
}

Replacement is one regex substitution.

type Rule

type Rule struct {
	// Name is the diagnostics / ledger-key label.
	Name string
	// Command matches the normalized command (program base + args joined by
	// single spaces, env assignments stripped), e.g. `^make\b`.
	Command *regexp.Regexp
	// Strip drops any line matching one of these.
	Strip []*regexp.Regexp
	// Keep, when non-empty, keeps only lines matching one of these (applied
	// after Strip).
	Keep []*regexp.Regexp
	// Replace applies regex substitutions before line filtering.
	Replace []Replacement
	// PassFail turns the command into a binary result: on success (exit 0)
	// the whole output collapses to a single "ok" line (OnEmpty if set, else
	// "<name>: ok") regardless of content; on failure it falls through to the
	// normal strip/keep pipeline (or raw, with KeepOnError) so the error is
	// still shown. For commands whose successful output is pure noise
	// (builds, formatters) and only the exit code matters.
	PassFail bool
	// Summarize collapses the whole output to Message when Pattern matches
	// AND the command succeeded (exit 0). This is the success-detection
	// short-circuit ("BUILD SUCCESSFUL" → "gradle: ok"); it never fires on a
	// failing run, so an error is never replaced by a rosy summary.
	Summarize []OutputMatch
	// MaxLines keeps the first N lines (0 = unbounded); TailLines keeps the
	// last N. Prefer leaving these zero on build/test commands so a late
	// error is never truncated — the universal cap still bounds runaways.
	MaxLines  int
	TailLines int
	// TruncateAt caps each line's length in bytes (0 = unbounded).
	TruncateAt int
	// OnEmpty is emitted when filtering removed everything ("make: ok").
	OnEmpty string
	// KeepOnError returns the raw output verbatim on a nonzero exit.
	KeepOnError bool
}

Rule is a declarative, data-driven filter — ask's equivalent of one of RTK's src/filters/*.toml files. A table of Rules (see rules.go) covers the long tail of commands without a bespoke Go type each; complex aggregators (go test, git, pytest) stay hand-written. Every Rule is registered as its own Filter through ruleFilter, so ordering and precedence work exactly like the hand-written filters.

Jump to

Keyboard shortcuts

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