Skip to main content

iterm2_client/
tab.rs

1//! High-level handle to an iTerm2 tab.
2
3use crate::connection::Connection;
4use crate::error::{Error, Result};
5use crate::proto;
6use crate::request;
7use crate::validate;
8use std::sync::Arc;
9use tokio::io::{AsyncRead, AsyncWrite};
10
11/// A handle to an iTerm2 tab.
12pub struct Tab<S> {
13    /// The unique tab identifier.
14    pub id: String,
15    conn: Arc<Connection<S>>,
16}
17
18impl<S: AsyncRead + AsyncWrite + Unpin + Send + 'static> Tab<S> {
19    /// Create a tab handle. Validates the tab ID.
20    pub fn new(id: String, conn: Arc<Connection<S>>) -> Result<Self> {
21        validate::identifier(&id, "tab")?;
22        Ok(Self { id, conn })
23    }
24
25    pub(crate) fn new_unchecked(id: String, conn: Arc<Connection<S>>) -> Self {
26        Self { id, conn }
27    }
28
29    /// Activate this tab (select it in its window).
30    pub async fn activate(&self) -> Result<()> {
31        let resp = self.conn.call(request::activate_tab(&self.id)).await?;
32        match resp.submessage {
33            Some(proto::server_originated_message::Submessage::ActivateResponse(r)) => {
34                check_status_i32(r.status, "Activate")
35            }
36            _ => Err(Error::UnexpectedResponse {
37                expected: "ActivateResponse",
38            }),
39        }
40    }
41
42    /// Close this tab. If `force` is true, skip the confirmation prompt.
43    pub async fn close(&self, force: bool) -> Result<()> {
44        let resp = self
45            .conn
46            .call(request::close_tabs(vec![self.id.clone()], force))
47            .await?;
48        match resp.submessage {
49            Some(proto::server_originated_message::Submessage::CloseResponse(_)) => Ok(()),
50            _ => Err(Error::UnexpectedResponse {
51                expected: "CloseResponse",
52            }),
53        }
54    }
55
56    /// Get a tab variable by name. Returns JSON-encoded value.
57    pub async fn get_variable(&self, name: &str) -> Result<Option<String>> {
58        let resp = self
59            .conn
60            .call(request::get_variable_tab(&self.id, vec![name.to_string()]))
61            .await?;
62        match resp.submessage {
63            Some(proto::server_originated_message::Submessage::VariableResponse(r)) => {
64                check_status_i32(r.status, "Variable")?;
65                Ok(r.values.into_iter().next())
66            }
67            _ => Err(Error::UnexpectedResponse {
68                expected: "VariableResponse",
69            }),
70        }
71    }
72
73    /// Get a reference to the underlying connection.
74    pub fn connection(&self) -> &Connection<S> {
75        &self.conn
76    }
77}
78
79fn check_status_i32(status: Option<i32>, op: &str) -> Result<()> {
80    match status {
81        Some(0) | None => Ok(()),
82        Some(code) => Err(Error::Status(format!("{op} returned status {code}"))),
83    }
84}