Core LibraryunreleasedConcepts

Choose documentation 1

latest

Current version

latest
English

Unreleased libtmux_erlang has not been released. Its API may change during development. This site's structure and URLs may change too.

Selections and queries

A snapshot is observed data. A selection is ordered rows plus their captured context. A filter is portable predicate data. A query describes a future tmux observation. Only fetch executes a query.

The README program shows both paths against real tmux. It retains a captured name after renaming the live window, then executes a fresh source query. All ordinary snapshot and selection reads stay local, even after the endpoint closes.

Criteria

Local criteria use atom-keyed maps and binary text. Bare scalars mean equality; fields and operators in one map conjoin. Boolean branches use quoted 'and', 'or' and 'not'. Empty AND is true and empty OR is false. Callbacks belong to tmux_select:filter/2 and must return Booleans; callback failures propagate.

Relations use some/every/none/count for to-many values and is/is_not for to-one values. One some containing two conditions requires the same related row. Two separate some conditions can match different rows. Empty to-many relations make some false and every and none true.

Fields and operators come from the runtime validator. Unknown fields, invalid operations, type mismatches and incomplete coverage fail before row traversal. An unloaded relationship never becomes an empty relationship. from_list keeps supplied order and duplicates but cannot infer relationships.

Cardinality

CallResult
first{ok, Row} or none; more matches are allowed
one{ok, Row}, {error, no_match}, or a multiple-match error
one_or_none{ok, Row}, {ok, none}, or a multiple-match error
one_or_errorRow directly; raises on zero or multiple matches
sizeCached materialized size
countCurrent size, or exact count after supplied criteria

Criteria come first and the selection last. Ambiguity stops after the second match once validation is complete. to_list/1 and fold/3 keep ordinary Erlang list consumers available; a selection is not a list protocol.

Portable input

tmux_filter:decode_json/1 rejects duplicate keys, trailing input and excessive size/depth. from_wire/2 maps generated wire names explicitly; it never creates atoms from payload keys. to_wire/1 exports filter data, not closures or native record internals. Integral numbers normalize only within the exact shared JSON integer range. Text is case-sensitive and is not implicitly normalized.

Run this complete local recipe. It uses captured rows and needs no tmux server:

Terminal window
$ mise exec -- escript tools/run_examples.escript filter
-module(filter_demo).
-moduledoc "Validate portable JSON and filter captured rows without tmux I/O.".
-export([run/0]).
-spec run() -> map().
run() ->
{ok, Editor} = tmux_model:pane(#{id => <<"%1">>, active => true,
width => 120, current_command => <<"nvim">>}),
{ok, Shell} = tmux_model:pane(#{id => <<"%2">>, active => false,
width => 80, current_command => <<"bash">>}),
Panes = tmux_select:from_list(pane, [Editor, Shell]),
Criteria = #{active => true, 'or' => [
#{current_command => #{in => [<<"nvim">>, <<"vim">>]}},
#{width => #{gte => 160}}
]},
{ok, Filter} = tmux_filter:new(pane, Criteria),
Encoded = iolist_to_binary(json:encode(tmux_filter:to_wire(Filter))),
{ok, Document} = tmux_filter:decode_json(Encoded),
{ok, RoundTrip} = tmux_filter:from_wire(pane, Document),
{ok, Editor} = tmux_select:one(RoundTrip, Panes),
[Editor] = tmux_select:to_list(tmux_select:where(Filter, Panes)),
{error, #{code := duplicate_key}} = tmux_filter:decode_json(
<<"{\"version\":1,\"version\":2}">>),
Invalid = #{active => #{contains => <<"yes">>}},
try tmux_select:where(Invalid, Panes) of
_ -> error(expected_validation_error)
catch
error:{bad_filter, #{code := unsupported_operator} = Detail}:Stack ->
[active, contains] = maps:get(path, Detail),
Reason = {bad_filter, Detail},
Message = erl_error:format_exception(error, Reason, Stack),
Text = unicode:characters_to_binary(Message),
{_, _} = binary:match(Text, <<"Allowed:">>)
end,
#{matched_ids => [tmux_model:get(id, Editor)],
wire_round_trip => true, duplicate_keys_rejected => true}.

It selects %1, preserves the meaning of the JSON round trip, and rejects ambiguous duplicate keys. The installed-archive check runs the same program.

The restricted ASCII regex guide gives its grammar and resource limits. Non-ASCII subjects and exhausted match limits are errors, not nonmatches. Local callbacks provide other regex semantics.

Source plans

Queries filter the complete captured graph locally by default. Enable native candidate exclusion explicitly with tmux_query:pushdown(true, Query). It can add a candidate scan and an earlier observation without reducing graph hydration. tmux_query:explain/1 reports the choice in its pushdown field.

tmux_query:explain/1 performs no I/O. It reports command templates, native candidate conditions, full residual data, complete hydration, required fields, ordering, identity policy and temporal assumptions. ID, Boolean and qualified unsigned numeric conditions can reach tmux’s -f. Text, nullable fields and relations remain local. Numeric comparisons use tmux arithmetic formats, not string ordering.

Hydration defaults to one framed list scan per nonempty entity collection. Each field is expanded once and escaped before row/column framing, preserving paths containing tabs, newlines and non-UTF-8 bytes. A successful nonempty capture uses nine logical commands, plus an optional candidate scan. Identity preflights add one tmux client per command. Linked memberships can increase the bytes returned even though physical rows remain unique.

Each command remains bounded to 1 MiB of stdout. If a whole entity exceeds that bound, use hydration => isolated in snapshot or fetch options to read one field per physical row. The total capture bound and deadline still apply. The hydration entry of the commands metadata describes the default templates; its isolated_hydration entry describes isolated reads and unqualified-schema fallback. Snapshot metadata records the chosen strategy and actual calls. ADR 0002 records the framing, measurements and tradeoffs.

A candidate is a necessary condition: it can admit extra rows but must not exclude a same-state full-filter match. Unsupported leaves become true; AND and OR compose conservatively; NOT translates only exact children. Membership trees are balanced to respect tmux’s recursion limit.

Fetch retains a complete captured graph, validates any candidate scalar agreement, evaluates the full local filter, and only then applies limits. Physical entities deduplicate by ID; window links retain membership identity. pushdown(false, Q) disables earlier candidate exclusion. Capture options bound rows, output and time; retry => 1 requests at most one inconsistent-capture retry within the original capture deadline. The default is no retry.

Captures span several commands and are not atomic. Local re-evaluation cannot recover rows excluded before their state changed. Atomic consistency and a same-connection identity promise remain unsupported by this one-shot path.

Esc

Type to search.

Reference previewOpen reference