# Captured queries

Source: https://libtmux.org/en/julia/latest/concepts/queries/

> Captured queries: LibTmux documentation.

[`snapshot`](https://libtmux.org/en/julia/latest/reference/libtmux-snapshot-1gv6/) acquires finite observations. [`panes(snap)`](<https://libtmux.org/en/julia/latest/reference/libtmux-panes/>) contains
unique physical panes; [`paneoccurrences(snap)`](<https://libtmux.org/en/julia/latest/reference/libtmux-paneoccurrences/>) follows each session/window
link and may contain the same pane more than once. Filtering preserves the
source's order and multiplicity.

[`PaneWhere`](https://libtmux.org/en/julia/latest/reference/libtmux-panewhere/), [`WindowWhere`](https://libtmux.org/en/julia/latest/reference/libtmux-windowwhere/), [`SessionWhere`](https://libtmux.org/en/julia/latest/reference/libtmux-sessionwhere/),
[`WindowLinkWhere`](https://libtmux.org/en/julia/latest/reference/libtmux-windowlinkwhere/) and [`ClientWhere`](https://libtmux.org/en/julia/latest/reference/libtmux-clientwhere/) are callable criteria.
Use them with Base `filter`, `count`, `any`, `all`, `findall` and
[`Iterators.filter`](https://docs.julialang.org/en/v1/base/iterators/#Base.Iterators.filter). Ordinary closures and downstream callable values work
where Base accepts them. `findall` returns collection positions; those are
one-based Julia indices, independent of tmux's configured indices.

`filter` preserves a [`Selection`](https://libtmux.org/en/julia/latest/reference/libtmux-selection/). `collect` and row projections give
ordinary Julia collections. A selection pins its snapshot; keeping one pane
can therefore retain the whole captured graph. Refreshing acquires a new
snapshot and never changes existing selections.

The complete shared-window example is included directly from its tested
source:

```julia title="shared_windows.jl"
using LibTmux
import LibTmux.Filters as F

function main()
    snap = with_server(; tmux=get(ENV, "LIBTMUX_TEST_TMUX", "tmux")) do server
        dev = new_session(server; name="dev", command=["/bin/cat"])
        initial = snapshot(server)
        api = only(windows(initial)).ref
        rename_window(server, api, "api")
        split_window(server, only(panes(initial)).ref; command=["/bin/cat"])
        new_window(server, dev; name="build", command=["/bin/cat"])

        ops = new_session(server; name="ops", command=["/bin/cat"])
        captured = snapshot(server)
        placeholder =
            only(windows(onlymatch(SessionWhere(name="ops"), sessions(captured)))).ref
        source = onlymatch(
            WindowLinkWhere(window=WindowWhere(name="api")),
            windowlinks(captured),
        )
        link_window(server, WindowLinkRef(source), ops; index=4)
        kill_window(server, placeholder)
        snapshot(server)
    end

    @assert length(sessions(snap)) == 2
    @assert length(windows(snap)) == 2
    @assert length(windowlinks(snap)) == 3
    @assert length(panes(snap)) == 3
    @assert length(paneoccurrences(snap)) == 5

    # Captured relations remain usable after the owned daemon has stopped.
    has_api = SessionWhere(windows=F.AnyRelated(WindowWhere(name="api")))
    @assert count(has_api, sessions(snap)) == 2
    selected = filter(PaneWhere(active=true, window=WindowWhere(name="api")), panes(snap))
    @assert length(selected) == 1
    @assert only(selected).ref ==
            only(Iterators.filter(p -> p.active && p.window.name == "api", panes(snap))).ref
    println("2 sessions, 2 windows, 3 links, 3 panes, 5 occurrences")
    snap
end

main()
```

Fields in one criterion are conjoined. Nested relations preserve correlation:
conditions within one [`AnyRelated(WindowWhere(...))`](<https://libtmux.org/en/julia/latest/reference/libtmux-filters-anyrelated/>) concern the same window.
Two separate [`AnyRelated`](<https://libtmux.org/en/julia/latest/reference/libtmux-filters-anyrelated/>) clauses can match different windows. On a captured
empty relation, any/all/none evaluates to false/true/true. Uncaptured membership
raises [`SnapshotCoverageError`](https://libtmux.org/en/julia/latest/reference/libtmux-snapshotcoverageerror/), including in short-circuited branches.

`only` keeps Base's zero/multiple-result errors. [`onlymatch`](https://libtmux.org/en/julia/latest/reference/libtmux-onlymatch/) adds
distinct [`NoMatchError`](https://libtmux.org/en/julia/latest/reference/libtmux-nomatcherror/) and [`MultipleMatchesError`](https://libtmux.org/en/julia/latest/reference/libtmux-multiplematcheserror/) diagnostics.

Portable criteria use [`encode_where`](https://libtmux.org/en/julia/latest/reference/libtmux-encode_where/) and [`decode_where`](https://libtmux.org/en/julia/latest/reference/libtmux-decode_where/).
Closures are local code and cannot be encoded. TypeScript and Rust adapters
are separately named and reject semantics outside their verified intersection.
JSON and Tables are optional extensions, not mandatory core dependencies.

Criterion construction and wire conversion are pure and can be checked without
a tmux executable:

```julia
julia> using LibTmux

julia> criterion = PaneWhere(active=true);

julia> criterion isa Function
true

julia> encode_where(decode_where(encode_where(criterion))) == encode_where(criterion)
true
```
