Filter captured values

Copy Markdown View Source

Obtain one snapshot, then select its observed panes:

alias LibTmux.{Selection, Snapshot}

editors =
  snapshot
  |> Snapshot.panes()
  |> Selection.where(active: true, current_command: [in: ["nvim", "vim"]])

Enum.map(editors, & &1.id)

Selections retain their immutable graph and order. Enumerable delegates to the materialized list, including suspension and early halt. size/1 uses the cached count; ordinary Enum.member?/2 compares elements. Use Selection.member_id?/2 for native ID membership. Enumeration performs no I/O.

Selection.filter/2 accepts only unary functions and uses Enum truthiness. Predicate exceptions propagate. where/2 accepts validated data: keywords are shorthand for maps, with duplicate keys rejected at every nesting level. Both validate before scanning, including when no items remain.

one/2 returns {:ok, item} or a structured :no_match / :multiple_matches error. one_or_nil/2 permits zero matches. Their bang variants raise the same error; both stop at the second match. exists?/2 stops at its first match. count/2 counts matching items; size/1 returns the cached total.

Predicate grammar

A bare scalar means equality. Explicit %{equals: value} is equivalent. The generated schema lists each field's type and operators. Numbers compare numerically, strings compare case-sensitively without normalization, and nullable numeric ordering against known nil is false. not negates equality; not_in negates membership, including known nil. Portable regex is not supported. Native predicates may use Regex directly.

Fields in one object conjoin. Boolean and and or accept lists of criteria; not accepts one criteria object. Empty and is true and empty or is false. Normalization never combines separate relation quantifiers:

Selection.where(Snapshot.sessions(snapshot), %{
  panes: %{some: %{active: true, current_command: "nvim"}}
})

That predicate requires one pane to satisfy both conditions. Two separate some clauses can match different panes. every and none are true for a known-empty relation; some is false. count counts that relation's identities: physical windows/panes deduplicate, window links retain memberships.

To-one is: criteria is false for known absence and is_not negates it. is: nil means absent; is_not: nil means present. Session active_window is derived from a complete link domain and loaded active flags. Zero active links means known absence; multiple active links raise :ambiguous_relation. An unresolved active target remains unloaded. Coverage checks run before evaluation, including fields behind a Boolean branch that cannot match.

External filters

Filter.new/3 returns a validated portable value, and new!/3 raises its structured error. Applying that value retains its constructor validation; explicit new limits validate the normalized tree without generating extra criteria objects. Prepared predicates may contain sets and closures; portable filters contain data only.

Filter.from_json/3 uses built-in JSON and rejects duplicate keys before map conversion, trailing data and unknown names. from_wire/3 accepts an already decoded map; that map cannot reveal discarded duplicate keys. Neither decoder creates atoms from external keys. Encode through Filter.to_wire/1, then JSON.encode!/1.

{"version":1,"entity":"pane","where":{"active":true,"currentCommand":{"in":["nvim","vim"]}}}

Default ceilings are 65,536 bytes, depth 16, 1024 value nodes, 256 array elements and 8192 bytes per string. Wire depth starts at root zero and counts every member/element; the ceiling is inclusive. Positive integer options max_bytes, max_depth, max_nodes, max_list and max_string_bytes can narrow or widen the constructor budget. JSON object members have a fixed ceiling of 256. Native input depth counts criteria objects and also bounds the normalized tree. A normalized conjunction does not add relation/Boolean nesting; disjunctions, negations and relation children do. Wire budgets additionally cover the full versioned envelope. Errors carry the affected path, including Boolean and membership indexes; early parser-limit errors can identify the root before a path is available.

Selections and filters operate on captured values. Server query planning and pushdown remain under implementation.