Compare commits

...

17 commits

Author SHA1 Message Date
0fc6cd66c6 renamed 'root' command to 'path' 2024-06-10 12:03:40 -04:00
1320b6f122 'h' is now shortened version of 'has' instead of help 2024-06-10 12:02:57 -04:00
26f6fd5dd0 made nest prevent message more helpful 2024-06-10 12:02:57 -04:00
19b12c682d updated README 2024-06-10 12:02:57 -04:00
28a7fc44f9 switched session enforce to new tmux detection helper 2024-06-10 12:02:57 -04:00
21eda33624 default window name now sets correctly 2024-06-10 12:02:57 -04:00
d776129b3e added help text for REMUX_NEW_WINDOW env var 2024-06-10 12:02:57 -04:00
62d72735da added REMUX_WINDOW_NAME var for add command 2024-06-10 12:02:57 -04:00
681e7427ba updated help text to include topics 2024-06-10 12:02:57 -04:00
d8aaf7feed corrected name of ATTACH_SYMBOL env var 2024-06-10 12:02:57 -04:00
b3403ffa36 wrote help topic for env vars 2024-06-10 12:02:57 -04:00
a07ae193b5 moved environment variable code to a new module 2024-06-10 12:02:02 -04:00
c8800a7f53 created env module 2024-06-10 12:01:15 -04:00
92d0010186 renamed detach flag and added detach support to 'new' 2024-06-10 12:01:15 -04:00
21f7b72298 removed incompatible disable_echo from session exist check 2024-06-10 12:01:15 -04:00
2e28acc3c3 version bump 2024-06-10 12:01:15 -04:00
e017d57a53 initial implementation of root command and made some commands allow being thrown through pipes 2024-06-10 12:01:15 -04:00
9 changed files with 138 additions and 39 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "remux" name = "remux"
version = "0.3.0" version = "0.3.1"
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"

View file

@ -17,10 +17,10 @@ shorter than its equivalent tmux command:
```sh ```sh
# new session # new session
tmux new-session -t foo tmux new-s -t foo
remux n foo remux n foo
# lists # list sessions
tmux ls tmux ls
remux l remux l
remux remux
@ -30,11 +30,11 @@ tmux a -t foo
remux a foo remux a foo
# has # has
tmux has -t foo tmux h -t foo
remux has foo remux h foo
# detach # detach
tmux detach-client -t foo tmux det -t foo
remux d foo remux d foo
# nesting sessions with '-n' flag # nesting sessions with '-n' flag
@ -43,6 +43,15 @@ remux a -n foo
TMUX='' tmux new-session -t foo TMUX='' tmux new-session -t foo
remux n -n foo remux n -n foo
# switch to another session
tmux swi -t foo
rmux s foo
# cd to session path
tmux run 'printf "#{session_path}" > /tmp/tmux_path'
cd `cat /tmp/tmux_path`
cd `rmux p`
``` ```
## Dependencies ## Dependencies

View file

@ -1,4 +1,5 @@
//! commands accessible from within a session //! commands accessible from within a session
use std::fs::read_to_string;
use pico_args::Arguments; use pico_args::Arguments;
use tmux_interface::{ use tmux_interface::{
@ -8,7 +9,10 @@ use tmux_interface::{
use crate::{ error, flag, util }; use crate::{ error, flag, util };
const TMP_ROOT: &str = "/tmp/remux_path";
pub fn switch(pargs: &mut Arguments) { pub fn switch(pargs: &mut Arguments) {
util::terminal_enforce();
// refuse to run outside a session // refuse to run outside a session
util::session_enforce("switch"); util::session_enforce("switch");
@ -32,3 +36,17 @@ pub fn switch(pargs: &mut Arguments) {
.output().ok(); .output().ok();
} }
pub fn path() {
util::session_enforce("path");
let exec = commands::Run::new().shell_command("printf '#{session_path}' > ".to_string() + TMP_ROOT);
Tmux::new()
.add_command(exec)
.output().ok();
if let Ok(text) = read_to_string(TMP_ROOT) {
println!("{text}");
std::fs::remove_file(TMP_ROOT).ok();
}
}

View file

@ -1,6 +1,5 @@
//! globally available tmux commands. //! globally available tmux commands.
use std::{ use std::{
env::var,
ffi::OsString, ffi::OsString,
process::exit process::exit
}; };
@ -12,15 +11,22 @@ use tmux_interface::{
commands commands
}; };
use crate::{ error, flag, util }; use crate::{
env::{ self, env_var },
error,
flag,
util
};
pub fn attach(pargs: &mut Arguments) { pub fn attach(pargs: &mut Arguments) {
// must be run from terminal
util::terminal_enforce();
// don't allow unflagged nests // don't allow unflagged nests
util::prevent_nest(); util::prevent_nest();
// consume optional flags // consume optional flags
let read_only = pargs.contains(flag::READ_ONLY); let read_only = pargs.contains(flag::READ_ONLY);
let detach_other = pargs.contains(flag::DETACHED); let detach_other = pargs.contains(flag::DETACH);
let args = pargs.clone().finish(); let args = pargs.clone().finish();
let target: String; let target: String;
@ -59,6 +65,7 @@ pub fn attach(pargs: &mut Arguments) {
} }
pub fn detach(pargs: &mut Arguments) { pub fn detach(pargs: &mut Arguments) {
util::terminal_enforce();
// get target or fallback // get target or fallback
let args = pargs.clone().finish(); let args = pargs.clone().finish();
let target: String; let target: String;
@ -119,7 +126,7 @@ pub fn list() {
} }
// get attached session symbol // get attached session symbol
let attach_symbol = var("REMUX_ATTACH_SYMBOL").unwrap_or("*".to_string()); let attach_symbol = env_var(env::ATTACH_SYMBOL);
// pretty print session list // pretty print session list
println!("sessions:"); println!("sessions:");
@ -142,12 +149,17 @@ pub fn list() {
} }
pub fn new(pargs: &mut Arguments) { pub fn new(pargs: &mut Arguments) {
util::terminal_enforce();
// don't allow unflagged nesting // don't allow unflagged nesting
util::prevent_nest(); util::prevent_nest();
// get optional flag // get optional flags
let detached = pargs.contains(flag::DETACH);
let target_dir: Result<String, Error> = pargs.value_from_str(flag::TARGET); let target_dir: Result<String, Error> = pargs.value_from_str(flag::TARGET);
// get environment variables
let window_name = env_var(env::NEW_WINDOW_NAME);
// get target or fallback // get target or fallback
let args = pargs.clone().finish(); let args = pargs.clone().finish();
let title: String; let title: String;
@ -164,10 +176,18 @@ pub fn new(pargs: &mut Arguments) {
let mut new = commands::NewSession::new(); let mut new = commands::NewSession::new();
new = new.group_name(title); new = new.group_name(title);
if let Some(command) = command { new.shell_command = Some(command.to_string_lossy()); } if let Some(command) = command { new.shell_command = Some(command.to_string_lossy()); }
if detached { new.detached = true; }
if let Ok(target_dir) = target_dir { new = new.start_directory(target_dir); } if let Ok(target_dir) = target_dir { new = new.start_directory(target_dir); }
Tmux::new() let mut tmux = Tmux::new().add_command(new);
.add_command(new)
.output().ok(); // rename window if var not empty
if !window_name.is_empty() {
let auto_name = commands::RenameWindow::new()
.new_name(window_name);
tmux = tmux.add_command(auto_name);
}
tmux.output().ok();
} }

13
src/env.rs Normal file
View file

@ -0,0 +1,13 @@
use std::env::var;
pub type EnvVar = (&'static str, &'static str);
pub static ATTACH_SYMBOL: EnvVar = ("REMUX_ATTACH_SYMBOL", "*");
pub static NEW_WINDOW_NAME: EnvVar = ("REMUX_NEW_WINDOW", "");
pub fn env_var(envvar: EnvVar) -> String {
var(envvar.0).unwrap_or(envvar.1.to_string())
}
pub fn tmux() -> bool { !var("TMUX").unwrap_or("".to_string()).is_empty() }

View file

@ -1,7 +1,7 @@
type Flag = [&'static str;2]; type Flag = [&'static str;2];
pub static DETACHED: Flag = ["-d", "--detached"]; pub static DETACH: Flag = ["-d", "--detach"];
pub static HELP: Flag = ["-h", "--help"]; pub static HELP: Flag = ["-h", "--help"];
pub static NEST: Flag = ["-n", "--nest"]; pub static NEST: Flag = ["-n", "--nest"];
pub static QUIET: Flag = ["-q", "--quiet"]; pub static QUIET: Flag = ["-q", "--quiet"];

View file

@ -16,14 +16,23 @@ A command wrapper for tmux written in Rust.
usage: remux <command> [<args>] usage: remux <command> [<args>]
commands: commands:
help Show help text for remux or a specific command help Show help text for remux, a command, or a help topic.
attach Attach to an existing tmux session attach Attach to an existing tmux session
detach Detach clients from a tmux session detach Detach clients from a tmux session
has Check if a tmux session exists has Check if a tmux session exists
list Pretty-print all tmux sessions list Pretty-print all tmux sessions
new Create a new tmux session new Create a new tmux session
Use 'remux help <command>' to see detailed help text for each command."), path print session path (session)
switch switch to another session (session)
Use 'remux help <command>' to see detailed help text for each command.
help topics:
env Environment variables"),
// COMMAND HELP
Some("a" | "attach") Some("a" | "attach")
=> =>
@ -53,12 +62,13 @@ usage: remux detach <session>
args: args:
<session> The session name to detach clients from"), <session> The session name to detach clients from"),
Some("has") Some("h" | "has")
=> =>
println!("remux has println!("remux has
Check if the target session exists. Check if the target session exists.
usage: remux has [flags] <session> usage: remux has [flags] <session>
rmux h [flags] session
args: args:
<session> The session to check for <session> The session to check for
@ -91,6 +101,15 @@ flags:
-n, --nest Create the session inside another session. -n, --nest Create the session inside another session.
-t, --target <dir> Sets the target directory for the new session."), -t, --target <dir> Sets the target directory for the new session."),
Some("root")
=>
println!("remux path
Print the session path (#{{session_path}}) to standard output.
Must be run from inside a session.
usage: remux path
remux p"),
Some("s" | "switch") Some("s" | "switch")
=> =>
println!("remux switch println!("remux switch
@ -106,6 +125,23 @@ args:
flags: flags:
-r, --read-only Attach the target session as read-only."), -r, --read-only Attach the target session as read-only."),
// TOPIC HELP
Some("env" | "vars")
=>
println!("remux environment variables
REMUX_ATTACH_SYMBOL
Changes the symbol displayed for attached sessions displayed
by the 'list' command.
Default: '*'
REMUX_NEW_WINDOW
Provides a default window name when creating a session with
the 'new' command, if not empty.
Default: ''"),
// not found // not found
_ => error::no_help(topic.unwrap()) _ => error::no_help(topic.unwrap())
} }

View file

@ -1,11 +1,9 @@
use std::{ use std::env::{ set_var, var };
env::{ set_var, var },
io::{ stdout, IsTerminal }
};
use pico_args::Arguments; use pico_args::Arguments;
mod command; mod command;
mod env;
mod error; mod error;
mod flag; mod flag;
mod help; mod help;
@ -39,13 +37,11 @@ fn main() {
set_var("TMUX", ""); set_var("TMUX", "");
} }
if !stdout().is_terminal() { error::not_terminal(); }
let subcommand = args.subcommand().unwrap(); let subcommand = args.subcommand().unwrap();
// invoke subcommand function // invoke subcommand function
match subcommand.as_deref() { match subcommand.as_deref() {
Some("h" | "help") Some("help")
=> help(&mut args), => help(&mut args),
Some("a" | "attach") Some("a" | "attach")
@ -54,7 +50,7 @@ fn main() {
Some("d" | "detach") Some("d" | "detach")
=> command::share::detach(&mut args), => command::share::detach(&mut args),
Some("has") Some("h" | "has")
=> command::share::has(&mut args), => command::share::has(&mut args),
None | None |
@ -64,6 +60,9 @@ fn main() {
Some("n" | "new") Some("n" | "new")
=> command::share::new(&mut args), => command::share::new(&mut args),
Some("p" | "path")
=> command::session::path(),
Some("s" | "switch") Some("s" | "switch")
=> command::session::switch(&mut args), => command::session::switch(&mut args),

View file

@ -1,5 +1,6 @@
use std::{ use std::{
env::{ current_dir, var }, env::current_dir,
io::{ stdout, IsTerminal },
path::PathBuf, path::PathBuf,
process::exit process::exit
}; };
@ -11,7 +12,10 @@ use tmux_interface::{
variables::session::SessionsCtl variables::session::SessionsCtl
}; };
use crate::error; use crate::{
env,
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>> {
@ -23,19 +27,15 @@ pub fn get_sessions() -> Option<Vec<Session>> {
/// show the tmux nest text if env var is not unset /// show the tmux nest text if env var is not unset
pub fn prevent_nest() { pub fn prevent_nest() {
let tmux = var("TMUX").ok(); if env::tmux() {
if tmux.is_some() && tmux.unwrap() != "" { println!("To nest sessions, use the -n flag.");
println!("Sessions should be nested with care; unset TMUX or use the '-n' flag to allow."); exit(6);
exit(1);
} }
} }
/// enforce a command is being used in-session /// enforce a command is being used in-session
pub fn session_enforce(cmd: &'static str) { pub fn session_enforce(cmd: &'static str) {
let tmux = var("TMUX").unwrap_or("".to_string()); if !env::tmux() { error::not_in_session(cmd); }
if tmux.is_empty() {
error::not_in_session(cmd);
}
} }
/// check whether a target session exists /// check whether a target session exists
@ -43,12 +43,16 @@ pub fn session_exists<S: Into<String>>(target: S) -> bool {
let has_session = commands::HasSession::new() let has_session = commands::HasSession::new()
.target_session(target.into()); .target_session(target.into());
Tmux::new().add_command(has_session) Tmux::new().add_command(has_session)
.disable_echo()
.status() .status()
.unwrap() .unwrap()
.success() .success()
} }
/// enforce a command is being run in a terminal
pub fn terminal_enforce() {
if !stdout().is_terminal() { error::not_terminal(); }
}
/// attempt to return the repo name or exit /// attempt to return the repo name or exit
pub fn repo_fallback() -> String { pub fn repo_fallback() -> String {
let repo = repo_root(current_dir().unwrap()); let repo = repo_root(current_dir().unwrap());