tmux_lib/
client.rs

1//! Client-level functions: for representing client state (`client_session` etc) or reporting information inside Tmux.
2
3use std::str::FromStr;
4
5use async_std::process::Command;
6use nom::{character::complete::char, combinator::all_consuming, sequence::tuple};
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    error::{map_add_intent, Error},
11    parse::{quoted_nonempty_string, quoted_string},
12    Result,
13};
14
15/// A Tmux client.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct Client {
18    /// The current session.
19    pub session_name: String,
20    /// The last session.
21    pub last_session_name: String,
22}
23
24impl FromStr for Client {
25    type Err = Error;
26
27    /// Parse a string containing client information into a new `Client`.
28    ///
29    /// This returns a `Result<Client, Error>` as this call can obviously
30    /// fail if provided an invalid format.
31    ///
32    /// The expected format of the tmux response is
33    ///
34    /// ```text
35    /// name-of-current-session:name-of-last-session
36    /// ```
37    ///
38    /// This status line is obtained with
39    ///
40    /// ```text
41    /// tmux display-message -p -F "'#{client_session}':'#{client_last_session}'"
42    /// ```
43    ///
44    /// For definitions, look at `Pane` type and the tmux man page for
45    /// definitions.
46    fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
47        let desc = "Client";
48        let intent = "'#{client_session}':'#{client_last_session}'";
49        let parser = tuple((quoted_nonempty_string, char(':'), quoted_string));
50
51        let (_, (session_name, _, last_session_name)) =
52            all_consuming(parser)(input).map_err(|e| map_add_intent(desc, intent, e))?;
53
54        Ok(Client {
55            session_name: session_name.to_string(),
56            last_session_name: last_session_name.to_string(),
57        })
58    }
59}
60
61// ------------------------------
62// Ops
63// ------------------------------
64
65/// Return the current client useful attributes.
66///
67/// # Errors
68///
69/// Returns an `io::IOError` in the command failed.
70pub async fn current() -> Result<Client> {
71    let args = vec![
72        "display-message",
73        "-p",
74        "-F",
75        "'#{client_session}':'#{client_last_session}'",
76    ];
77
78    let output = Command::new("tmux").args(&args).output().await?;
79    let buffer = String::from_utf8(output.stdout)?;
80
81    Client::from_str(buffer.trim_end())
82}
83
84/// Return a list of all `Pane` from all sessions.
85///
86/// # Panics
87///
88/// This function panics if it can't communicate with Tmux.
89pub fn display_message(message: &str) {
90    let args = vec!["display-message", message];
91
92    std::process::Command::new("tmux")
93        .args(&args)
94        .output()
95        .expect("Cannot communicate with Tmux for displaying message");
96}
97
98/// Switch to session exactly named `session_name`.
99
100pub async fn switch_client(session_name: &str) -> Result<()> {
101    let exact_session_name = format!("={session_name}");
102    let args = vec!["switch-client", "-t", &exact_session_name];
103
104    Command::new("tmux")
105        .args(&args)
106        .output()
107        .await
108        .expect("Cannot communicate with Tmux for switching the client");
109
110    Ok(())
111}