From e7d2f797db872edc250d7be1b7d3c2594250169d Mon Sep 17 00:00:00 2001 From: Dlurak <84224239+Dlurak@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:59:28 +0200 Subject: [PATCH] Add some flags --- .github/workflows/rust.yml | 23 +++++++++ src/cli.rs | 98 -------------------------------------- src/cli/directory.rs | 41 ++++++++++++++++ src/cli/mod.rs | 33 +++++++++++++ src/cli/template.rs | 47 ++++++++++++++++++ src/commands/directory.rs | 35 ++++++-------- src/commands/template.rs | 51 +++++++++++++++----- src/templates.rs | 1 + src/tmux.rs | 11 +++++ 9 files changed, 210 insertions(+), 130 deletions(-) create mode 100644 .github/workflows/rust.yml delete mode 100644 src/cli.rs create mode 100644 src/cli/directory.rs create mode 100644 src/cli/mod.rs create mode 100644 src/cli/template.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..4d94ae0 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,23 @@ +name: Rust + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build + run: cargo build --verbose + - name: Run Clippy + run: cargo clippy --verbose + - name: Run tests + run: cargo test --verbose diff --git a/src/cli.rs b/src/cli.rs deleted file mode 100644 index d9b6cf8..0000000 --- a/src/cli.rs +++ /dev/null @@ -1,98 +0,0 @@ -use clap::{Parser, Subcommand}; -use std::path::PathBuf; - -// TODO: Make a `cli`directory with multiple files - -/// A CLI for tmux session management -#[derive(Parser, Debug)] -#[clap(version)] -pub struct Cli { - #[command(subcommand)] - pub cmd: Commands, -} - -#[derive(Subcommand, Debug)] -pub enum Commands { - /// Initialize the config - /// - /// This command will initialize your config directories. - Init, - /// Manage directories in the context of muxmate and tmux - /// - /// This command provides functionalities to interact with tmux sessions based on directories. - #[command(alias = "dir", alias = "dirs", alias = "directories")] - Directory(DirectoryCli), - /// Manage templates in the context of muxmate and tmux - /// - /// This command provides functionalities to interact with tmux sessions based on templates - #[command(alias = "temp", alias = "templ")] - Template(TemplateCli), -} - -#[derive(Parser, Debug)] -pub struct DirectoryCli { - #[command(subcommand)] - pub action: DirectoryCommands, -} - -#[derive(Subcommand, Debug)] -pub enum DirectoryCommands { - #[command(alias = "ls")] - List(ListArgs), - Start(StartDirectoryArgs), -} - -#[derive(Parser, Debug)] -pub struct ListArgs { - /// Show minimal output for scripts - #[arg(short, long, default_value_t = false)] - pub minimal: bool, -} - -#[derive(Parser, Debug)] -pub struct StartDirectoryArgs { - /// The directory to start the session in - pub directory: String, - - /// Start the session detached - #[arg(short, long, default_value_t = false)] - pub detached: bool, - - /// Specify the name of the tmux session - /// - /// Optionally provide a name for the session. If not provided, it will be either the name from the configuration or from the directory - #[arg(short, long)] - pub name: Option, -} - -#[derive(Parser, Debug)] -pub struct TemplateCli { - #[command(subcommand)] - pub action: TemplateCommands, -} - -#[derive(Subcommand, Debug)] -pub enum TemplateCommands { - #[command(alias = "ls")] - List(ListArgs), - Start(StartTemplateArgs), -} - -#[derive(Parser, Debug)] -pub struct StartTemplateArgs { - pub template_name: String, - - /// Start the session detached - #[arg(short, long, default_value_t = false)] - pub detached: bool, - - /// The directory to start it in - #[arg(long, alias = "dir")] - pub directory: Option, - - /// Specify the name of the tmux session - /// - /// Optionally provide a name for the session. If not provided, it will be either the name from the configuration or from the directory - #[arg(short, long)] - pub name: Option, -} diff --git a/src/cli/directory.rs b/src/cli/directory.rs new file mode 100644 index 0000000..ea4f838 --- /dev/null +++ b/src/cli/directory.rs @@ -0,0 +1,41 @@ +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +pub struct DirectoryCli { + #[command(subcommand)] + pub action: DirectoryCommands, +} + +#[derive(Subcommand, Debug)] +pub enum DirectoryCommands { + #[command(alias = "ls")] + List(ListDirectoryArgs), + Start(StartDirectoryArgs), +} + +#[derive(Parser, Debug)] +pub struct ListDirectoryArgs { + /// Show minimal output for scripts + #[arg(short, long, default_value_t = false)] + pub minimal: bool, +} + +#[derive(Parser, Debug)] +pub struct StartDirectoryArgs { + /// The directory to start the session in + pub directory: String, + + /// Start the session detached + #[arg(short, long, default_value_t = false)] + pub detached: bool, + + /// Specify the name of the tmux session + /// + /// Optionally provide a name for the session. If not provided, it will be either the name from the configuration or from the directory + #[arg(short, long)] + pub name: Option, + + /// Always start a new session instead of attaching to an existing session + #[arg(long, default_value_t = false)] + pub always_new_session: bool, +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs new file mode 100644 index 0000000..f8a6479 --- /dev/null +++ b/src/cli/mod.rs @@ -0,0 +1,33 @@ +pub mod directory; +pub mod template; + +use clap::{Parser, Subcommand}; +use self::{directory::DirectoryCli, template::TemplateCli}; + +// TODO: Make a `cli`directory with multiple files + +/// A CLI for tmux session management +#[derive(Parser, Debug)] +#[clap(version)] +pub struct Cli { + #[command(subcommand)] + pub cmd: Commands, +} + +#[derive(Subcommand, Debug)] +pub enum Commands { + /// Initialize the config + /// + /// This command will initialize your config directories. + Init, + /// Manage directories in the context of muxmate and tmux + /// + /// This command provides functionalities to interact with tmux sessions based on directories. + #[command(alias = "dir", alias = "dirs", alias = "directories")] + Directory(DirectoryCli), + /// Manage templates in the context of muxmate and tmux + /// + /// This command provides functionalities to interact with tmux sessions based on templates + #[command(alias = "temp", alias = "templ")] + Template(TemplateCli), +} diff --git a/src/cli/template.rs b/src/cli/template.rs new file mode 100644 index 0000000..ec307ef --- /dev/null +++ b/src/cli/template.rs @@ -0,0 +1,47 @@ +use clap::{Parser, Subcommand}; +use std::path::PathBuf; +#[derive(Parser, Debug)] +pub struct TemplateCli { + #[command(subcommand)] + pub action: TemplateCommands, +} + +#[derive(Subcommand, Debug)] +pub enum TemplateCommands { + #[command(alias = "ls")] + List(ListTemplateArgs), + Start(StartTemplateArgs), +} + +#[derive(Parser, Debug)] +pub struct ListTemplateArgs { + /// Show minimal output for scripts + #[arg(short, long, default_value_t = false)] + pub minimal: bool, + /// Show all templates including hidden ones + #[arg(short, long, default_value_t = false)] + pub all: bool, +} + +#[derive(Parser, Debug)] +pub struct StartTemplateArgs { + pub template_name: String, + + /// Start the session detached + #[arg(short, long, default_value_t = false)] + pub detached: bool, + + /// The directory to start it in + #[arg(long, alias = "dir")] + pub directory: Option, + + /// Specify the name of the tmux session + /// + /// Optionally provide a name for the session. If not provided, it will be either the name from the configuration or from the directory + #[arg(short, long)] + pub name: Option, + + /// Always start a new session instead of attaching to an existing session + #[arg(long, default_value_t = false)] + pub always_new_session: bool, +} diff --git a/src/commands/directory.rs b/src/commands/directory.rs index fd7590e..ef350e9 100644 --- a/src/commands/directory.rs +++ b/src/commands/directory.rs @@ -1,12 +1,8 @@ use crate::{ - cli::{DirectoryCli, DirectoryCommands, ListArgs, StartDirectoryArgs}, - directories::{self, Directory}, - helpers::{absolute_path, dir_name, Exit}, - tmux::{attach, session_exists}, - widgets::{heading::Heading, table::fmt_table}, + cli::directory::{DirectoryCli, DirectoryCommands, ListDirectoryArgs, StartDirectoryArgs}, conditional_command, directories::{self, Directory}, helpers::{absolute_path, dir_name, Exit}, tmux::{attach, session_exists}, widgets::{heading::Heading, table::fmt_table} }; use std::{collections::HashMap, path::PathBuf}; -use tmux_interface::{NewSession, Tmux}; +use tmux_interface::{NewSession, Tmux, TmuxCommand}; pub fn directory_handler(args: DirectoryCli) { match args.action { @@ -15,7 +11,7 @@ pub fn directory_handler(args: DirectoryCli) { } } -fn list_handler(args: ListArgs) { +fn list_handler(args: ListDirectoryArgs) { let config = directories::parse_directory_config(); let categories = config.categories; @@ -47,24 +43,21 @@ fn start_handler(args: StartDirectoryArgs) { let (name, path) = resolve_dir_path(&args); let exists = session_exists(&name).unwrap_or(false); - if !exists { - let new_session_cmd = NewSession::new() + let new_session_cmd = conditional_command!( + args.always_new_session || !exists, + NewSession::new() .start_directory(path.to_string_lossy()) .detached() .session_name(&name) - .window_name(&name); - Tmux::new() - .add_command(new_session_cmd) - .output() - .exit(1, "Could not start Tmux-session"); - } + .window_name(&name) + ); + let attach_cmd = conditional_command!(!args.detached, attach(&name)); - if !args.detached { - Tmux::new() - .add_command(attach(&name)) - .output() - .exit(1, "Could not switch to the Tmux session"); - } + Tmux::new() + .add_command(new_session_cmd) + .add_command(attach_cmd) + .output() + .exit(1, "Could not switch to the Tmux session"); } fn resolve_dir_path(cli_args: &StartDirectoryArgs) -> (String, PathBuf) { diff --git a/src/commands/template.rs b/src/commands/template.rs index 3017e14..befa758 100644 --- a/src/commands/template.rs +++ b/src/commands/template.rs @@ -1,6 +1,6 @@ use crate::{ apply_if, - cli::{ListArgs, StartTemplateArgs, TemplateCli, TemplateCommands}, + cli::template::{ListTemplateArgs, StartTemplateArgs, TemplateCli, TemplateCommands}, helpers::{absolute_path, dir_name, Exit}, templates::{apply_template, parse_template_config}, tmux::{attach, session_exists}, @@ -16,10 +16,18 @@ pub fn template_handler(args: TemplateCli) { } } -fn list_handler(args: ListArgs) { +fn list_handler(args: ListTemplateArgs) { let templates = parse_template_config(); + let filtered = if args.all { + templates + } else { + templates + .into_iter() + .filter(|t| !t.hidden.unwrap_or(false)) + .collect() + }; - for template in templates { + for template in filtered { if args.minimal { println!("{}", template.name); } else { @@ -37,33 +45,54 @@ fn start_handler(args: StartTemplateArgs) { .exit(1, "No template found"); let detached = args.detached; - let name = &template.name; + let resolved_path = args.directory.and_then(|p| absolute_path(&p).ok()); + let name = resolved_path + .as_ref() + .map(|p| dir_name(p)) + .unwrap_or(template.name.clone()); - if session_exists(name).unwrap_or(false) { + if session_exists(&name).unwrap_or(false) && !args.always_new_session { apply_if!(!detached, Tmux::new(), add_command, attach(name)) .output() .exit(1, "Could not attach to the Tmux-session"); return; } - let resolved_path = args.directory.and_then(|p| absolute_path(&p).ok()); - let (new_session_cmd, name) = resolve_cmd_name(&resolved_path, args.name, name.to_string()); + let (new_session_cmd, name) = resolve_cmd_name(&resolved_path, args.name, name); - let initial_tmux = Tmux::new().add_command(new_session_cmd); - let initial_tmux = apply_if!(!detached, initial_tmux, add_command, attach(&name)); + let initial_tmux = apply_if!( + !detached, + Tmux::new().add_command(new_session_cmd), + add_command, + attach(&name) + ); let tmux = apply_template(initial_tmux, &template, &resolved_path); tmux.output().exit(1, "Could not start Tmux-session"); } +fn get_unused_name(name: String, used: Option) -> String { + let new_name = match used { + Some(counter) => format!("{}({})", name, counter), + None => name.clone(), + }; + + if session_exists(&new_name).unwrap_or(false) { + let next_counter = used.unwrap_or(0) + 1; + get_unused_name(name, Some(next_counter)) + } else { + new_name + } +} + fn resolve_cmd_name( path: &Option, name: Option, template_name: String, ) -> (TmuxCommand<'static>, String) { if let Some(p) = path { - let session_name = name.unwrap_or_else(|| dir_name(p)); + let session_name = get_unused_name(name.unwrap_or_else(|| dir_name(p)), None); return ( NewSession::new() .detached() @@ -74,7 +103,7 @@ fn resolve_cmd_name( ); } - let session_name = name.unwrap_or(template_name); + let session_name = get_unused_name(name.unwrap_or(template_name), None); ( NewSession::new() .detached() diff --git a/src/templates.rs b/src/templates.rs index d3dca4b..cfe1b31 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -9,6 +9,7 @@ use tmux_interface::{Tmux, TmuxCommand}; #[derive(Deserialize, Debug)] pub struct Template { pub name: String, + pub hidden: Option, pub windows: Vec, } diff --git a/src/tmux.rs b/src/tmux.rs index 03a6c6e..4b6b254 100644 --- a/src/tmux.rs +++ b/src/tmux.rs @@ -16,3 +16,14 @@ pub fn session_exists<'a, S: Into>>(name: S) -> Result .output() .map(|x| x.success()) } + +#[macro_export] +macro_rules! conditional_command { + ($condition:expr, $command:expr) => { + if $condition { + $command.into() + } else { + TmuxCommand::new() + } + }; +}