tmux_lib/
pane_id.rs

1//! Pane id.
2
3use std::fmt;
4use std::str::FromStr;
5
6use nom::{
7    character::complete::{char, digit1},
8    combinator::all_consuming,
9    sequence::preceded,
10    IResult,
11};
12use serde::{Deserialize, Serialize};
13
14use crate::error::{map_add_intent, Error};
15
16/// The id of a Tmux pane.
17///
18/// This wraps the raw tmux representation (`%12`).
19#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub struct PaneId(pub String);
21
22impl FromStr for PaneId {
23    type Err = Error;
24
25    /// Parse into `PaneId`. The `&str` must start with '%' followed by a `u32`.
26    fn from_str(input: &str) -> Result<Self, Self::Err> {
27        let desc = "PaneId";
28        let intent = "#{pane_id}";
29
30        let (_, pane_id) =
31            all_consuming(parse::pane_id)(input).map_err(|e| map_add_intent(desc, intent, e))?;
32
33        Ok(pane_id)
34    }
35}
36
37impl From<&u16> for PaneId {
38    fn from(value: &u16) -> Self {
39        Self(format!("%{value}"))
40    }
41}
42
43impl PaneId {
44    /// Extract a string slice containing the raw representation.
45    #[must_use]
46    pub fn as_str(&self) -> &str {
47        &self.0
48    }
49}
50
51impl fmt::Display for PaneId {
52    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53        write!(f, "{}", self.0)
54    }
55}
56
57pub(crate) mod parse {
58    use super::{char, digit1, preceded, IResult, PaneId};
59
60    pub(crate) fn pane_id(input: &str) -> IResult<&str, PaneId> {
61        let (input, digit) = preceded(char('%'), digit1)(input)?;
62        let id = format!("%{digit}");
63        Ok((input, PaneId(id)))
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn test_parse_pane_id_fn() {
73        let actual = parse::pane_id("%43");
74        let expected = Ok(("", PaneId("%43".into())));
75        assert_eq!(actual, expected);
76
77        let actual = parse::pane_id("%4");
78        let expected = Ok(("", PaneId("%4".into())));
79        assert_eq!(actual, expected);
80    }
81
82    #[test]
83    fn test_parse_pane_id_struct() {
84        let actual = PaneId::from_str("%43");
85        assert!(actual.is_ok());
86        assert_eq!(actual.unwrap(), PaneId("%43".into()));
87
88        let actual = PaneId::from_str("4:38");
89        assert!(matches!(
90            actual,
91            Err(Error::ParseError {
92                desc: "PaneId",
93                intent: "#{pane_id}",
94                err: _
95            })
96        ));
97    }
98}