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 nom::{character::complete::char, combinator::all_consuming, Parser};
6use serde::{Deserialize, Serialize};
7use smol::process::Command;
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 = (quoted_nonempty_string, char(':'), quoted_string);
50
51        let (_, (session_name, _, last_session_name)) = all_consuming(parser)
52            .parse(input)
53            .map_err(|e| map_add_intent(desc, intent, e))?;
54
55        Ok(Client {
56            session_name: session_name.to_string(),
57            last_session_name: last_session_name.to_string(),
58        })
59    }
60}
61
62// ------------------------------
63// Ops
64// ------------------------------
65
66/// Return the current client useful attributes.
67///
68/// # Errors
69///
70/// Returns an `io::IOError` in the command failed.
71pub async fn current() -> Result<Client> {
72    let args = vec![
73        "display-message",
74        "-p",
75        "-F",
76        "'#{client_session}':'#{client_last_session}'",
77    ];
78
79    let output = Command::new("tmux").args(&args).output().await?;
80    let buffer = String::from_utf8(output.stdout)?;
81
82    Client::from_str(buffer.trim_end())
83}
84
85/// Return a list of all `Pane` from all sessions.
86///
87/// # Panics
88///
89/// This function panics if it can't communicate with Tmux.
90pub fn display_message(message: &str) {
91    let args = vec!["display-message", message];
92
93    std::process::Command::new("tmux")
94        .args(&args)
95        .output()
96        .expect("Cannot communicate with Tmux for displaying message");
97}
98
99/// Switch to session exactly named `session_name`.
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}