use std::{ffi::OsString, path::PathBuf, process::Command, time::Duration}; use crate::{parser::Parser, project::Project}; use self::error::Error; pub mod error; #[derive(Debug)] pub struct Tmux; impl Tmux { pub fn sessions() -> Result, Error> { let stdout = Command::new("tmux") .arg("list-sessions") .arg("-F") .arg("#{session_path}") .output()? .stdout; Ok(std::str::from_utf8(&stdout)? .lines() .map(Into::into) .collect()) } pub fn get_session(&self, path_buf: PathBuf) -> Result { let mut filter = OsString::from("#{==:#{session_path},"); filter.push(path_buf.as_os_str()); filter.push("}"); // tmux list-sessions -f '#{==:#{session_path},/home/tobyv/src/projectr}' let stdout = Command::new("tmux") .arg("list-sessions") .arg("-F") .arg("#{session_path},#{session_last_attached},#{session_created}") .arg("-f") .arg(filter) .output()? .stdout; std::str::from_utf8(&stdout)? .lines() .map(Self::parse_project) .inspect(|res| { if let Err(err) = res { tracing::warn!(%err, "Skipping invalid format") } }) .flatten() .max() .ok_or(Error::NotFound) } fn parse_project>(fmt_str: T) -> Result { let mut split = fmt_str.as_ref().split(','); let path_buf = split .next() .ok_or(Error::PathFormat(fmt_str.as_ref().to_string()))? .into(); let timestamp = split .next() .ok_or(Error::TimestampFormat(fmt_str.as_ref().to_string()))? .parse() .map(Duration::from_secs)?; Ok(Project { timestamp, path_buf, }) } } impl Parser for Tmux { type Error = Error; fn parse(&self, path_buf: PathBuf) -> Result { self.get_session(path_buf) } }