upgraded tmux_interface to 0.3.2 and restructured command module

This commit is contained in:
Valerie Wolfe 2024-03-06 15:54:41 -05:00
parent be5bace0ac
commit aba802e77d
7 changed files with 209 additions and 192 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "remux" name = "remux"
version = "0.2.0" version = "0.3.0"
edition = "2021" edition = "2021"
authors = [ "Valerie Wolfe <sleeplessval@gmail.com>" ] authors = [ "Valerie Wolfe <sleeplessval@gmail.com>" ]
description = "A friendly command shortener for tmux" description = "A friendly command shortener for tmux"
@ -15,7 +15,7 @@ path = "src/main.rs"
[dependencies] [dependencies]
pico-args = { version = "0.5.0", features = [ "combined-flags", "eq-separator" ] } pico-args = { version = "0.5.0", features = [ "combined-flags", "eq-separator" ] }
termion = "2.0.1" termion = "2.0.1"
tmux_interface = "0.2.1" tmux_interface = "0.3.2"
[profile.release] [profile.release]
opt-level = 's' opt-level = 's'

View file

@ -1,170 +0,0 @@
use std::{
env::current_dir,
ffi::OsString,
process::exit
};
use pico_args::Arguments;
use termion::{ color, style };
use tmux_interface::TmuxCommand;
use crate::error;
use crate::util;
pub fn attach(pargs: &mut Arguments) {
util::prevent_nest();
// get optional flags
let read_only = pargs.contains(["-r", "--readonly"]);
let detach_other = pargs.contains(["-d", "--detach"]);
// collect target and window arguments
let args = pargs.clone().finish();
let target: String;
let window: Option<&OsString>;
if args.len() < 1 {
// missing name will attempt to fall back to repository
target = util::repo_fallback();
if !util::session_exists(target.clone()) { error::missing_target(); }
window = None;
} else {
target = args.get(0).unwrap().to_string_lossy().to_string();
window = args.get(1);
}
// focus window if provided
if window.is_some() {
let target = window.unwrap().to_string_lossy();
TmuxCommand::new()
.select_window()
.target_window(target)
.output().ok();
}
// make sure the target session exists
let exists = util::session_exists(target.clone());
if !exists { error::no_target(target.clone()); }
// build command
let mut attach = TmuxCommand::new().attach_session();
// handle optional flags
if read_only { attach.read_only(); }
if detach_other { attach.detach_other(); }
// run command
attach
.target_session(target)
.output().ok();
}
pub fn detach(pargs: &mut Arguments) {
// get target and error out if not provided
let args = pargs.clone().finish();
if args.len() < 1 { error::missing_target(); }
let target = args.get(0).unwrap().to_string_lossy();
// make sure the target session exists
let exists = util::session_exists(target.clone());
if !exists { error::no_target(target.clone()); }
// build command and run
TmuxCommand::new()
.detach_client()
.target_session(target)
.output().ok();
}
pub fn has(pargs: &mut Arguments) {
// get optional flag
let quiet = pargs.contains(["-q", "--quiet"]);
// collect target argument
let args = pargs.clone().finish();
let target: String;
if args.len() < 1 {
// missing name will attempt to fall back to repository
target = util::repo_fallback();
} else {
target = args.get(0).unwrap().to_string_lossy().to_string();
}
// run command
let success = util::session_exists(target.clone());
// handle optional flag
// inverted; print text if NOT quiet
if !quiet { println!("session \"{target}\" {}.", if success { "exists" } else { "does not exist" }); }
// exit codes for scripts to use
exit( if success { 0 } else { 1 });
}
pub fn list() {
// get session list
let sessions = util::get_sessions().unwrap_or(Vec::new());
// handle empty case
if sessions.len() == 0 {
println!("no sessions");
return;
}
// iterate over pretty print
println!("sessions:");
for session in sessions.into_iter() {
let group = session.group.unwrap_or("[untitled]".to_string());
let id = session.id.unwrap();
let attached = session.attached.unwrap_or(0) > 0;
println!(
" {group} ({bold}{blue}{id}{reset}) {bold}{green}{attach_sym}{reset}",
// values
attach_sym = if attached { "󰌹" } else {""},
// formatting
bold = style::Bold,
blue = color::Fg(color::Blue),
green = color::Fg(color::LightGreen),
reset = style::Reset
);
}
}
pub fn new(pargs: &mut Arguments) {
use pico_args::Error;
// show nest message
util::prevent_nest();
// get optional flag
let target_dir: Result<String, Error> = pargs.value_from_str(["-t", "--target"]);
// get target and error out if not provided
let args = pargs.clone().finish();
// collect name and command arguments
let title: String;
let command: Option<&OsString>;
if args.len() < 1 {
// missing name will attempt to fall back to repository
title = util::repo_fallback();
command = None;
} else {
title = args.get(0).unwrap().to_string_lossy().to_string();
command = args.get(1);
}
// build command
let mut new = TmuxCommand::new().new_session();
// handle shell command argument
if command.is_some() { new.shell_command(command.unwrap().to_string_lossy()); }
// run command
new
.group_name(title)
.attach()
.start_directory(target_dir.unwrap_or(current_dir().unwrap().to_string_lossy().to_string()))
.output().ok();
}

4
src/command/mod.rs Normal file
View file

@ -0,0 +1,4 @@
pub mod share;
//pub mod session;

170
src/command/share.rs Normal file
View file

@ -0,0 +1,170 @@
//! globally available tmux commands.
use std::{
ffi::OsString,
process::exit
};
use pico_args::{ Arguments, Error };
use termion::{ color, style };
use tmux_interface::{
Tmux,
commands
};
use crate::{ error, flag, util };
pub fn attach(pargs: &mut Arguments) {
// don't allow unflagged nests
util::prevent_nest();
// consume optional flags
let read_only = pargs.contains(flag::READ_ONLY);
let detach_other = pargs.contains(flag::DETACHED);
let args = pargs.clone().finish();
let target: String;
let window: Option<&OsString>;
if args.len() < 1 {
// missing name will attempt to fall back to repository
target = util::repo_fallback();
if !util::session_exists(target.clone()) { error::missing_target(); }
window = None;
} else {
target = args.get(0).unwrap().to_string_lossy().to_string();
window = args.get(1);
}
// make sure the session exists
let exists = util::session_exists(target.clone());
if !exists { error::no_target(target.clone()); }
// build attach command
let mut attach = commands::AttachSession::new();
attach = attach.target_session(target);
if read_only { attach.read_only = true; }
if detach_other { attach.detach_other = true; }
let select_window: Option<commands::SelectWindow>;
if let Some(window) = window {
let mut command = commands::SelectWindow::new();
command.target_window = Some(window.to_string_lossy());
select_window = Some(command);
} else { select_window = None; }
// build dispatch
let mut tmux = Tmux::new().add_command(attach);
if let Some(select_window) = select_window { tmux = tmux.add_command(select_window); }
tmux.output().ok();
}
pub fn detach(pargs: &mut Arguments) {
// get target or fallback
let args = pargs.clone().finish();
let target: String;
if args.len() < 1 {
target = util::repo_fallback();
} else {
target = args.get(0).unwrap().to_string_lossy().to_string();
}
// make sure the session exists
let exists = util::session_exists(target.clone());
if !exists { error::no_target(target.clone()); }
// build and dispatch
let detach = commands::DetachClient::new()
.target_session(target);
Tmux::new()
.add_command(detach)
.output().ok();
}
pub fn has(pargs: &mut Arguments) {
// consume optional flags
let quiet = pargs.contains(flag::QUIET);
// get target or fallback
let args = pargs.clone().finish();
let target: String;
if args.len() < 1 {
target = util::repo_fallback();
} else {
target = args.get(0).unwrap().to_string_lossy().to_string();
}
// run command
let success = util::session_exists(target.clone());
// print if not quiet
if !quiet {
println!("session \"{target}\" {}.",
if success { "exists" }
else { "does not exist" }
);
}
// emit exit code
exit( if success { 0 } else { 1 });
}
pub fn list() {
// get session list
let sessions = util::get_sessions().unwrap_or(Vec::new());
// handle empty case
if sessions.len() == 0 {
println!("no sessions");
return;
}
// pretty print session list
println!("sessions:");
for session in sessions.into_iter() {
let group = session.group.unwrap_or("[untitled]".to_string());
let id = session.id.unwrap();
let attached = session.attached.unwrap_or(0) > 0;
println!(
" {group} ({bold}{blue}{id}{reset}) {bold}{green}{attach_sym}{reset}",
// value
attach_sym = if attached { "\u{F0339}" } else { "" },
// formatting
bold = style::Bold,
blue = color::Fg(color::Blue),
green = color::Fg(color::LightGreen),
reset = style::Reset
);
}
}
pub fn new(pargs: &mut Arguments) {
// don't allow unflagged nesting
util::prevent_nest();
// get optional flag
let target_dir: Result<String, Error> = pargs.value_from_str(flag::TARGET);
// get target or fallback
let args = pargs.clone().finish();
let title: String;
let command: Option<&OsString>;
if args.len() < 1 {
// attempt repo fallback
title = util::repo_fallback();
command = None;
} else {
title = args.get(0).unwrap().to_string_lossy().to_string();
command = args.get(1);
}
let mut new = commands::NewSession::new();
new = new.group_name(title);
if let Some(command) = command { new.shell_command = Some(command.to_string_lossy()); }
if let Ok(target_dir) = target_dir { new = new.start_directory(target_dir); }
Tmux::new()
.add_command(new)
.output().ok();
}

11
src/flag.rs Normal file
View file

@ -0,0 +1,11 @@
type Flag = [&'static str;2];
pub static DETACHED: Flag = ["-d", "--detached"];
pub static HELP: Flag = ["-h", "--help"];
pub static NEST: Flag = ["-n", "--nest"];
pub static QUIET: Flag = ["-q", "--quiet"];
pub static READ_ONLY: Flag = ["-r", "--read-only"];
pub static TARGET: Flag = ["-t", "--target"];
pub static VERSION: Flag = ["-v", "--version"];

View file

@ -7,6 +7,7 @@ use pico_args::Arguments;
mod command; mod command;
mod error; mod error;
mod flag;
mod help; mod help;
mod util; mod util;
@ -19,17 +20,17 @@ fn main() {
let mut args = Arguments::from_env(); let mut args = Arguments::from_env();
// consume flags // consume flags
if args.contains(["-h", "--help"]) { if args.contains(flag::HELP) {
help(&mut args); help(&mut args);
return; return;
} }
if args.contains(["-v", "--version"]) { if args.contains(flag::VERSION) {
version(); version();
return; return;
} }
let nesting = args.contains(["-n", "--nest"]); let nesting = args.contains(flag::NEST);
let tmux_var = var("TMUX").ok(); let tmux_var = var("TMUX").ok();
if nesting { if nesting {
if tmux_var.is_none() { if tmux_var.is_none() {
@ -48,20 +49,20 @@ fn main() {
=> help(&mut args), => help(&mut args),
Some("a" | "attach") Some("a" | "attach")
=> command::attach(&mut args), => command::share::attach(&mut args),
Some("d" | "detach") Some("d" | "detach")
=> command::detach(&mut args), => command::share::detach(&mut args),
Some("has") Some("has")
=> command::has(&mut args), => command::share::has(&mut args),
None | None |
Some("l" | "ls" | "list") Some("l" | "ls" | "list")
=> command::list(), => command::share::list(),
Some("n" | "new") Some("n" | "new")
=> command::new(&mut args), => command::share::new(&mut args),
_ _
=> error::no_subcommand(subcommand.unwrap()) => error::no_subcommand(subcommand.unwrap())

View file

@ -5,20 +5,20 @@ use std::{
}; };
use tmux_interface::{ use tmux_interface::{
Session, Sessions, TmuxCommand, Session, Tmux,
variables::session::session::SESSION_ALL
commands,
variables::session::SessionsCtl
}; };
use crate::error; use crate::error;
/// return a Vec of all sessions or None /// return a Vec of all sessions or None
pub fn get_sessions() -> Option<Vec<Session>> { pub fn get_sessions() -> Option<Vec<Session>> {
let i_sessions = Sessions::get(SESSION_ALL); let sessions = SessionsCtl::new().get_all();
if i_sessions.is_err() { return None; } if let Ok(sessions) = sessions {
let sessions = i_sessions.ok(); return Some(sessions.0);
if sessions.is_none() { return None; } } else { return None; }
Some(sessions.unwrap().0)
} }
/// show the tmux nest text if env var is not unset /// show the tmux nest text if env var is not unset
@ -32,10 +32,11 @@ pub fn prevent_nest() {
/// check whether a target session exists /// check whether a target session exists
pub fn session_exists<S: Into<String>>(target: S) -> bool { pub fn session_exists<S: Into<String>>(target: S) -> bool {
TmuxCommand::new() let has_session = commands::HasSession::new()
.has_session() .target_session(target.into());
.target_session(target.into()) Tmux::new().add_command(has_session)
.output().unwrap() .status()
.unwrap()
.success() .success()
} }