use std::collections::{HashMap, HashSet};
#[cfg(feature = "query")]
use std::fmt;
use std::sync::Arc;
use super::Server;
use crate::client::Client;
use crate::internal::listing::{self, Pushdown as _};
use crate::pane::Pane;
#[cfg(feature = "query")]
use crate::query::{FilterSchema, Filterable, ManyRelation};
use crate::session::Session;
#[cfg(feature = "query")]
use crate::snapshot::{SessionFields, WindowFields};
use crate::window::Window;
use crate::{Error, PaneId, SessionId, WindowId};
impl Server {
pub async fn windows(&self) -> Result<Vec<Window>, Error> {
let projections = listing::windows(&self.core, listing::Scope::Server, None).await?;
Ok(projections
.into_iter()
.map(|projection| Window::new(Arc::clone(&self.core), projection))
.collect())
}
pub async fn panes(&self) -> Result<Vec<Pane>, Error> {
let projections = listing::panes(&self.core, listing::Scope::Server, None).await?;
Ok(projections
.into_iter()
.map(|projection| Pane::new(Arc::clone(&self.core), projection))
.collect())
}
pub async fn clients(&self) -> Result<Vec<Client>, Error> {
let infos = listing::clients(&self.core, None).await?;
Ok(infos
.into_iter()
.map(|info| Client::new(Arc::clone(&self.core), info))
.collect())
}
pub async fn session(&self, name: impl AsRef<[u8]>) -> Result<Option<Session>, Error> {
let name = name.as_ref();
Ok(self
.sessions()
.await?
.into_iter()
.find(|session| session.name() == name))
}
pub async fn session_by_id(&self, id: &SessionId) -> Result<Option<Session>, Error> {
let infos = listing::sessions(&self.core, Some(&id.predicate("session_id"))).await?;
Ok(infos
.into_iter()
.next()
.map(|info| Session::new(Arc::clone(&self.core), info)))
}
pub async fn window_by_id(&self, id: &WindowId) -> Result<Option<Window>, Error> {
let projections = listing::windows(
&self.core,
listing::Scope::Server,
Some(&id.predicate("window_id")),
)
.await?;
Ok(projections
.into_iter()
.min_by_key(|projection| {
(
!projection.link().is_active(),
projection.link().identity().window_index(),
)
})
.map(|projection| Window::new(Arc::clone(&self.core), projection)))
}
pub async fn pane_by_id(&self, id: &PaneId) -> Result<Option<Pane>, Error> {
let projections = listing::panes(
&self.core,
listing::Scope::Server,
Some(&id.predicate("pane_id")),
)
.await?;
Ok(projections
.into_iter()
.next()
.map(|projection| Pane::new(Arc::clone(&self.core), projection)))
}
pub async fn client(&self, name: impl AsRef<[u8]>) -> Result<Option<Client>, Error> {
let name = name.as_ref();
Ok(self
.clients()
.await?
.into_iter()
.find(|client| client.name() == name))
}
pub async fn hierarchy(&self) -> Result<Vec<SessionTree>, Error> {
let (sessions, windows, panes) =
tokio::try_join!(self.sessions(), self.windows(), self.panes(),)?;
let mut seen = HashSet::new();
let mut panes_by_window: HashMap<u32, Vec<Pane>> = HashMap::new();
for pane in panes {
if !seen.insert(pane.id().number()) {
continue;
}
panes_by_window
.entry(pane.window_id().number())
.or_default()
.push(pane);
}
let mut windows_by_session: HashMap<u32, Vec<WindowTree>> = HashMap::new();
for window in windows {
let panes = panes_by_window
.get(&window.id().number())
.cloned()
.unwrap_or_default();
windows_by_session
.entry(window.session_id().number())
.or_default()
.push(WindowTree { window, panes });
}
Ok(sessions
.into_iter()
.map(|session| {
let windows = windows_by_session
.remove(&session.id().number())
.unwrap_or_default();
SessionTree { session, windows }
})
.collect())
}
pub async fn has_session(&self, name: impl AsRef<[u8]>) -> Result<bool, Error> {
let name = name.as_ref();
Ok(self
.sessions()
.await?
.iter()
.any(|session| session.name() == name))
}
pub async fn sessions(&self) -> Result<Vec<Session>, Error> {
let infos = listing::sessions(&self.core, None).await?;
Ok(infos
.into_iter()
.map(|info| Session::new(Arc::clone(&self.core), info))
.collect())
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct SessionTree {
pub session: Session,
pub windows: Vec<WindowTree>,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct WindowTree {
pub window: Window,
pub panes: Vec<Pane>,
}
#[cfg(feature = "query")]
#[non_exhaustive]
pub struct SessionTreeFields {
pub session: SessionFields<SessionTree>,
pub windows: ManyRelation<SessionTree, WindowTree>,
}
#[cfg(feature = "query")]
impl fmt::Debug for SessionTreeFields {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("SessionTreeFields")
.finish_non_exhaustive()
}
}
#[cfg(feature = "query")]
#[non_exhaustive]
pub struct WindowTreeFields {
pub window: WindowFields<WindowTree>,
pub panes: ManyRelation<WindowTree, Pane>,
}
#[cfg(feature = "query")]
impl fmt::Debug for WindowTreeFields {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("WindowTreeFields")
.finish_non_exhaustive()
}
}
#[cfg(feature = "query")]
const WINDOWS_RELATION: &str = "windows";
#[cfg(feature = "query")]
const PANES_RELATION: &str = "panes";
#[cfg(feature = "query")]
impl Filterable for SessionTree {
type Fields = SessionTreeFields;
const FILTER_TARGET: &'static str = "session_tree";
fn filter_fields() -> Self::Fields {
Self::Fields {
session: SessionFields::for_target(Self::FILTER_TARGET),
windows: crate::query::__private::many_relation(Self::FILTER_TARGET, WINDOWS_RELATION),
}
}
fn __filter_matches(&self, predicate: &crate::query::__private::Predicate) -> bool {
if predicate.field() == WINDOWS_RELATION {
return predicate.matches_many(&self.windows);
}
self.session.__filter_matches(predicate)
}
fn __filter_validate(
predicate: &crate::query::__private::Predicate,
) -> Result<(), crate::query::FilterExpressionError> {
if predicate.field() == WINDOWS_RELATION {
return predicate.validate_many::<WindowTree>();
}
<Session as Filterable>::__filter_validate(predicate)
}
}
#[cfg(feature = "query")]
impl FilterSchema for SessionTree {
fn __filter_schema() -> crate::query::__private::FilterSchemaDescriptor {
<Session as FilterSchema>::__filter_schema()
.retarget(Self::FILTER_TARGET)
.with_field(crate::query::__private::FilterFieldSchema::new(
WINDOWS_RELATION,
crate::query::__private::FilterValueSchema::Many(
crate::query::__private::filter_schema::<WindowTree>,
),
))
}
}
#[cfg(feature = "query")]
impl Filterable for WindowTree {
type Fields = WindowTreeFields;
const FILTER_TARGET: &'static str = "window_tree";
fn filter_fields() -> Self::Fields {
Self::Fields {
window: WindowFields::for_target(Self::FILTER_TARGET),
panes: crate::query::__private::many_relation(Self::FILTER_TARGET, PANES_RELATION),
}
}
fn __filter_matches(&self, predicate: &crate::query::__private::Predicate) -> bool {
if predicate.field() == PANES_RELATION {
return predicate.matches_many(&self.panes);
}
self.window.__filter_matches(predicate)
}
fn __filter_validate(
predicate: &crate::query::__private::Predicate,
) -> Result<(), crate::query::FilterExpressionError> {
if predicate.field() == PANES_RELATION {
return predicate.validate_many::<Pane>();
}
<Window as Filterable>::__filter_validate(predicate)
}
}
#[cfg(feature = "query")]
impl FilterSchema for WindowTree {
fn __filter_schema() -> crate::query::__private::FilterSchemaDescriptor {
<Window as FilterSchema>::__filter_schema()
.retarget(Self::FILTER_TARGET)
.with_field(crate::query::__private::FilterFieldSchema::new(
PANES_RELATION,
crate::query::__private::FilterValueSchema::Many(
crate::query::__private::filter_schema::<Pane>,
),
))
}
}