# Queries

Source: https://libtmux.org/en/scala/latest/guides/query/

> Queries: io.github.libtmux:libtmux-scala_3 documentation.

Acquire once, then use Scala collections. A handle's captured fields (`.info`,
returning the real Java [`PaneState`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-snapshot-panestate-panestate/>)/[`WindowState`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-snapshot-windowstate-windowstate/>)/[`SessionState`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-snapshot-sessionstate-sessionstate/>)/[`ClientState`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-snapshot-clientstate-clientstate/>)
record) describe state as of that capture. A `filter`, `find`, `collect`, sort
or comprehension over a [`Vector`](<https://docs.oracle.com/en/java/javase/21/docs/api/java/util/Vector.html>) of handles does not acquire another
snapshot. A custom predicate can still perform whatever work its author puts
inside it.

## Native predicates

`config` identifies the server. Keep the capture while deriving several views
of the same data. A view defers local computation; it does not refresh tmux.

<!-- snippet: scala-sync: query-native -->
```scala
import io.github.libtmux.scaladsl.{config => _, *}
import scala.util.Using

Using.resource(Server.open(config)) { server =>
  val panes = server.panes()
  val named = panes.filter(_.info.title().nonEmpty)
  val paths = panes.collect {
    case pane if pane.info.pid().isPresent => pane.info.currentPath()
  }
  val firstActive = panes.find(_.info.active())
  val deferred = panes.view.filter(_.info.title().nonEmpty)
  assert(deferred.toVector == named)
  assert(paths.size <= panes.size)
  assert(firstActive.forall(_.info.active()))
}
```

Missing metadata answers through the record's own Java accessor ([`Optional`](<https://docs.oracle.com/en/java/javase/21/docs/api/java/util/Optional.html>),
[`OptionalLong`](<https://docs.oracle.com/en/java/javase/21/docs/api/java/util/OptionalLong.html>)): a missing PID is different from PID zero, and unavailable
floating-pane metadata is different from [`Optional.of(false)`](<https://docs.oracle.com/en/java/javase/21/docs/api/java/util/Optional.html#of(T)>).

## The typed field DSL and strict cardinality

Fields hang on the handle type's own companion ([`Pane.command`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-pane-command/>), [`Pane.active`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-pane-active/>),
...), generated one-line forwards to Java's own field metamodel
([`Pane_.command()`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane_-pane_-command/>)). [`.matching`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-vector-matching/>) filters a captured [`Vector`](<https://docs.oracle.com/en/java/javase/21/docs/api/java/util/Vector.html>) locally; `&&`,
`||` and `!` compose expressions, alongside their named forms [`.and`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-query-filterexpr-filterexpr-and-12cg/>), [`.or`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-query-filterexpr-filterexpr-or-6b3f/>)
and [`.not`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-expr-not/>). [`.exactlyOne`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-query-selections-selections-exactlyone/>)/[`.atMostOne`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-iterableonce-atmostone/>) give the strict cardinality `headOption`
and `find` do not: both return `Either[CardinalityError, ...]`, mirroring
Java's own [`CardinalityException`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-exception-cardinalityexception-cardinalityexception/>) leaves losslessly, including
[`MultipleMatches`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-exception-cardinalityexception-cardinalityexception-multiplematches/>)'s [`atLeast`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-fields-numberfield-atleast/>) count.

<!-- snippet: scala-sync: query-cardinality -->
```scala
import io.github.libtmux.scaladsl.query.*

assert(Vector.empty[Int].atMostOne == Right(None))
assert(Vector("selected").exactlyOne == Right("selected"))
val ambiguous = Vector(1, 2).atMostOne
assert(ambiguous == Left(CardinalityError.MultipleMatches(2)))
```

## Symbolic and named operators

<!-- snippet: scala-sync: query-java-expression -->
```scala
import io.github.libtmux.scaladsl.{config => _, *}
import io.github.libtmux.scaladsl.query._
import scala.util.Using

Using.resource(Server.open(config)) { server =>
  val panes = server.panes()
  val expression = Pane.command.is("cat") && Pane.width.atLeast(1)
  val selected = panes.matching(expression)
  val native = panes.filter(p => p.info.currentCommand() == "cat" && p.info.size().width() >= 1)
  assert(selected == native)
}
```

The Cats module reads the same expressions over a captured [`Vector`](<https://docs.oracle.com/en/java/javase/21/docs/api/java/util/Vector.html>), inside
the effect's own `map`: `server.panes.map(_.filter(...))` (`Vector[Pane[F]]`
does not itself carry [`.matching`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-vector-matching/>) — apply the predicate to each pane's own
`.info` field instead, or to `.underlying.asJava` for a Java expression). This
is still local evaluation over a captured vector; it does not run a Java
command.

An invalid field/operator combination must fail at compilation:

<!-- snippet: scala-reject: query-invalid-op | contains is not a member -->
```scala
import io.github.libtmux.scaladsl.Pane
Pane.active.contains("yes")
```

## Relationships and identity

Java's [`Session_`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-session_-session_/>), [`Window_`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-window_-window_/>), [`Pane_`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane_-pane_/>) and [`Client_`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-client_-client_/>) expose the canonical
fields; the Scala field companions are one-line forwards to them, never a
second, hand-copied metamodel. Use their existing [`any`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-fields-tomanyref-any/>), `all`, [`none`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-fields-tomanyref-none/>) and
to-one `is` relations, exposed through [`Fields.ToManyRef`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-fields-tomanyref/>)/[`Fields.ToOneRef`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-fields-tooneref/>).
`all` over an empty relation is true. Applying [`any`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-fields-tomanyref-any/>) to a conjunction requires
one related object satisfying both conditions; conjoining two separate [`any`](<https://libtmux.org/en/scala/latest/reference/io-github-libtmux-scaladsl-query-fields-tomanyref-any/>)
expressions allows two different related objects.

Window equality includes its session and index placement. Pane equality is
physical, while traversal retains each occurrence's window context. A vector
can therefore contain equal pane handles reached through different links.
Deduplicate only when that is the intended question, retaining server identity
when mixing endpoints. See [ownership](https://libtmux.org/en/scala/latest/guides/ownership/).

## Serialization and regular expressions

Opted-in serialization uses the separate Java `libtmux-jackson` artifact and
its `libtmux.filter/1` schema, over the raw Java [`FilterExpr`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-query-filterexpr-filterexpr/>) an `Expr[T]`
wraps (`.asJava`). Keep the canonical Java field and relation objects;
rebuilding an accessor with the same name does not establish model authority.
Unknown schemas, fields, operators and relations remain errors. Arbitrary
Scala closures are not serialized.

Java regex matching uses [`java.util.regex.Pattern`](<https://docs.oracle.com/en/java/javase/21/docs/api/java/util/regex/Pattern.html>) and substring search through
[`Matcher.find`](<https://docs.oracle.com/en/java/javase/21/docs/api/java/util/regex/Matcher.html#find(int)>). Supply a Scala regex's `.pattern` explicitly. Neither the
expression adapter nor serialization implies tmux `-f` compilation or an MCP
query parameter.
