diff --git a/Cargo.lock b/Cargo.lock index 972914db..d61a653e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" [[package]] name = "arc-swap" @@ -715,9 +715,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "enumset" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e76129da36102af021b8e5000dab2c1c30dbef85c1e482beeff8da5dde0e0b0" +checksum = "6216d2c19a6fb5f29d1ada1dc7bc4367a8cbf0fa4af5cf12e07b5bbdde6b5b2c" dependencies = [ "enumset_derive", ] @@ -1149,9 +1149,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" [[package]] name = "libloading" @@ -1424,9 +1424,9 @@ checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "openssl-sys" -version = "0.9.67" +version = "0.9.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" +checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf" dependencies = [ "autocfg", "cc", @@ -1604,9 +1604,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] @@ -1931,9 +1931,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" dependencies = [ "itoa", "ryu", @@ -2127,9 +2127,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", @@ -2834,6 +2834,7 @@ dependencies = [ name = "zellij" version = "0.20.0" dependencies = [ + "anyhow", "insta", "log", "names", diff --git a/Cargo.toml b/Cargo.toml index 9f23cf87..1c33bae7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ rust-version = "1.56" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0" names = "0.11.0" zellij-client = { path = "zellij-client/", version = "0.20.0" } zellij-server = { path = "zellij-server/", version = "0.20.0" } diff --git a/src/main.rs b/src/main.rs index be11f170..f12eb010 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,9 @@ mod tests; use crate::install::populate_data_dir; use sessions::{ - assert_session, assert_session_ne, get_active_session, get_sessions, kill_session, - list_sessions, print_sessions, session_exists, ActiveSession, + assert_session, assert_session_ne, get_active_session, get_sessions, + get_sessions_sorted_by_creation_date, kill_session, list_sessions, print_sessions, + print_sessions_with_index, session_exists, ActiveSession, }; use std::process; use zellij_client::{os_input_output::get_client_os_input, start_client, ClientInfo}; @@ -111,6 +112,7 @@ pub fn main() { if let Some(Command::Sessions(Sessions::Attach { session_name, create, + index, options, })) = opts.command.clone() { @@ -119,47 +121,94 @@ pub fn main() { None => config_options, }; - let (client, attach_layout) = match session_name.as_ref() { - Some(session) => { - if create { - if !session_exists(session).unwrap() { - (ClientInfo::New(session_name.unwrap()), layout) + let (client, attach_layout) = if let Some(idx) = index { + // Ignore session_name when `--index` is provided + match get_sessions_sorted_by_creation_date() { + Ok(sessions) => { + if sessions.is_empty() { + if create { + ( + ClientInfo::New(names::Generator::default().next().unwrap()), + layout, + ) + } else { + println!("No active zellij sessions found."); + process::exit(1); + } } else { + match sessions.get(idx) { + Some(session) => ( + ClientInfo::Attach(session.clone(), config_options.clone()), + None, + ), + None => { + if create { + ( + ClientInfo::New( + names::Generator::default().next().unwrap(), + ), + layout, + ) + } else { + println!("No session indexed by {} found. The following sessions are active:", idx); + print_sessions_with_index(sessions); + process::exit(1); + } + } + } + } + } + Err(e) => { + eprintln!("Error occurred: {:?}", e); + process::exit(1); + } + } + } else { + match session_name.as_ref() { + Some(session) => { + if create { + if !session_exists(session).unwrap() { + (ClientInfo::New(session_name.unwrap()), layout) + } else { + ( + ClientInfo::Attach( + session_name.unwrap(), + config_options.clone(), + ), + None, + ) + } + } else { + assert_session(session); ( ClientInfo::Attach(session_name.unwrap(), config_options.clone()), None, ) } - } else { - assert_session(session); - ( - ClientInfo::Attach(session_name.unwrap(), config_options.clone()), - None, - ) } - } - None => match get_active_session() { - ActiveSession::None => { - if create { - ( - ClientInfo::New(names::Generator::default().next().unwrap()), - layout, - ) - } else { - println!("No active zellij sessions found."); + None => match get_active_session() { + ActiveSession::None => { + if create { + ( + ClientInfo::New(names::Generator::default().next().unwrap()), + layout, + ) + } else { + println!("No active zellij sessions found."); + process::exit(1); + } + } + ActiveSession::One(session_name) => ( + ClientInfo::Attach(session_name, config_options.clone()), + None, + ), + ActiveSession::Many => { + println!("Please specify the session name to attach to. The following sessions are active:"); + print_sessions(get_sessions().unwrap()); process::exit(1); } - } - ActiveSession::One(session_name) => ( - ClientInfo::Attach(session_name, config_options.clone()), - None, - ), - ActiveSession::Many => { - println!("Please specify the session name to attach to. The following sessions are active:"); - print_sessions(get_sessions().unwrap()); - process::exit(1); - } - }, + }, + } }; start_client( diff --git a/src/sessions.rs b/src/sessions.rs index 6a48a4f3..bf44d088 100644 --- a/src/sessions.rs +++ b/src/sessions.rs @@ -1,4 +1,5 @@ use std::os::unix::fs::FileTypeExt; +use std::time::SystemTime; use std::{fs, io, process}; use zellij_utils::{ consts::ZELLIJ_SOCK_DIR, @@ -29,6 +30,36 @@ pub(crate) fn get_sessions() -> Result, io::ErrorKind> { } } +pub(crate) fn get_sessions_sorted_by_creation_date() -> anyhow::Result> { + match fs::read_dir(&*ZELLIJ_SOCK_DIR) { + Ok(files) => { + let mut sessions_with_creation_date: Vec<(String, SystemTime)> = Vec::new(); + for file in files { + let file = file?; + let file_name = file.file_name().into_string().unwrap(); + let file_created_at = file.metadata()?.created()?; + if file.file_type()?.is_socket() && assert_socket(&file_name) { + sessions_with_creation_date.push((file_name, file_created_at)); + } + } + sessions_with_creation_date.sort_by_key(|x| x.1); // the oldest one will be the first + + let sessions = sessions_with_creation_date + .iter() + .map(|x| x.0.clone()) + .collect(); + Ok(sessions) + } + Err(err) => { + if let io::ErrorKind::NotFound = err.kind() { + Ok(Vec::with_capacity(0)) + } else { + Err(err.into()) + } + } + } +} + fn assert_socket(name: &str) -> bool { let path = &*ZELLIJ_SOCK_DIR.join(name); match LocalSocketStream::connect(path) { @@ -59,6 +90,18 @@ pub(crate) fn print_sessions(sessions: Vec) { }) } +pub(crate) fn print_sessions_with_index(sessions: Vec) { + let curr_session = std::env::var("ZELLIJ_SESSION_NAME").unwrap_or_else(|_| "".into()); + for (i, session) in sessions.iter().enumerate() { + let suffix = if curr_session == *session { + " (current)" + } else { + "" + }; + println!("{}: {}{}", i, session, suffix); + } +} + pub(crate) enum ActiveSession { None, One(String), diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index 7ac9e958..78615d92 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -85,6 +85,10 @@ pub enum Sessions { #[structopt(short, long)] create: bool, + /// Number of the session index in the active sessions ordered creation date. + #[structopt(long)] + index: Option, + /// Change the behaviour of zellij #[structopt(subcommand, name = "options")] options: Option,