From 5eef0632fb4563220800301189f95203af46f009 Mon Sep 17 00:00:00 2001 From: Dlurak <84224239+Dlurak@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:55:48 +0200 Subject: [PATCH] Add a start command for projects --- src/cli/project.rs | 14 +++++++++++ src/commands/directory.rs | 2 +- src/commands/project.rs | 50 ++++++++++++++++++++++++++++++++++++++- src/commands/template.rs | 30 +++++++---------------- src/projects.rs | 27 ++++++++++++++++----- src/templates.rs | 6 ++--- src/tmux.rs | 20 +++++++++++++++- src/widgets/table.rs | 27 +++++---------------- 8 files changed, 121 insertions(+), 55 deletions(-) diff --git a/src/cli/project.rs b/src/cli/project.rs index ade24d2..6530a70 100644 --- a/src/cli/project.rs +++ b/src/cli/project.rs @@ -10,6 +10,7 @@ pub struct ProjectCli { pub enum ProjectCommands { #[command(alias = "ls")] List(ProjectListArgs), + Start(ProjectStartArgs), } #[derive(Debug, Parser)] @@ -18,3 +19,16 @@ pub struct ProjectListArgs { #[arg(short, long, default_value_t = false)] pub minimal: bool, } + +#[derive(Debug, Parser)] +pub struct ProjectStartArgs { + pub name: String, + + /// Start the session detached + #[arg(short, long, default_value_t = false)] + pub detached: bool, + + /// 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 303ef17..985ac91 100644 --- a/src/commands/directory.rs +++ b/src/commands/directory.rs @@ -7,7 +7,7 @@ use crate::{ widgets::{heading::Heading, table::Table}, }; use std::{collections::HashMap, path::PathBuf}; -use tmux_interface::{NewSession, Tmux, TmuxCommand}; +use tmux_interface::{NewSession, Tmux}; pub fn directory_handler(args: DirectoryCli) { match args.action { diff --git a/src/commands/project.rs b/src/commands/project.rs index 358d442..90d839e 100644 --- a/src/commands/project.rs +++ b/src/commands/project.rs @@ -1,12 +1,18 @@ use crate::{ - cli::project::{ProjectCli, ProjectCommands, ProjectListArgs}, + apply_if, + cli::project::{ProjectCli, ProjectCommands, ProjectListArgs, ProjectStartArgs}, + helpers::{self, Exit}, projects::parse_project_config, + templates::apply_windows, + tmux, widgets::{heading::Heading, table::Table}, }; +use tmux_interface::{NewSession, Tmux}; pub fn project_handler(args: ProjectCli) { match args.action { ProjectCommands::List(args) => list_handler(args), + ProjectCommands::Start(args) => start_handler(args), } } @@ -20,3 +26,45 @@ fn list_handler(args: ProjectListArgs) { } } } + +fn start_handler(args: ProjectStartArgs) { + let projects = parse_project_config(); + let project = projects + .into_iter() + .find(|proj| proj.name == args.name) + .exit(1, "Project could not be found"); + + let detached = args.detached; + + if tmux::session_exists(&project.name).unwrap_or(false) && !args.always_new_session { + apply_if!( + !detached, + Tmux::new(), + add_command, + tmux::attach(&project.name) + ) + .output() + .exit(1, "Could not attach to the Tmux-session"); + return; + } + + let name = tmux::get_unused_name(project.name); + let windows = Vec::from(project.setup); + let path = helpers::absolute_path(&project.root_dir).exit(1, "The path could not be found"); + + let new_session_cmd = NewSession::new() + .detached() + .session_name(&name) + .start_directory(path.to_string_lossy().into_owned()); + + let initial_tmux = apply_if!( + !detached, + Tmux::new().add_command(new_session_cmd), + add_command, + tmux::attach(&name) + ); + + apply_windows(initial_tmux, &windows, &Some(path)) + .output() + .exit(1, "Could not start Tmux-session"); +} diff --git a/src/commands/template.rs b/src/commands/template.rs index d708891..9bc506c 100644 --- a/src/commands/template.rs +++ b/src/commands/template.rs @@ -2,8 +2,8 @@ use crate::{ apply_if, cli::template::{ListTemplateArgs, StartTemplateArgs, TemplateCli, TemplateCommands}, helpers::{absolute_path, dir_name, Exit}, - templates::{apply_template, parse_template_config}, - tmux::{attach, session_exists}, + templates::{apply_windows, parse_template_config}, + tmux, widgets::{heading::Heading, table::Table}, }; use std::path::PathBuf; @@ -51,8 +51,8 @@ fn start_handler(args: StartTemplateArgs) { .map(|p| dir_name(p)) .unwrap_or(template.name.clone()); - if session_exists(&name).unwrap_or(false) && !args.always_new_session { - apply_if!(!detached, Tmux::new(), add_command, attach(name)) + if tmux::session_exists(&name).unwrap_or(false) && !args.always_new_session { + apply_if!(!detached, Tmux::new(), add_command, tmux::attach(name)) .output() .exit(1, "Could not attach to the Tmux-session"); return; @@ -64,35 +64,21 @@ fn start_handler(args: StartTemplateArgs) { !detached, Tmux::new().add_command(new_session_cmd), add_command, - attach(&name) + tmux::attach(&name) ); - let tmux = apply_template(initial_tmux, &template, &resolved_path); + let tmux = apply_windows(initial_tmux, &template.windows, &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 = get_unused_name(name.unwrap_or_else(|| dir_name(p)), None); + let session_name = tmux::get_unused_name(name.unwrap_or_else(|| dir_name(p))); return ( NewSession::new() .detached() @@ -103,7 +89,7 @@ fn resolve_cmd_name( ); } - let session_name = get_unused_name(name.unwrap_or(template_name), None); + let session_name = tmux::get_unused_name(name.unwrap_or(template_name)); ( NewSession::new() .detached() diff --git a/src/projects.rs b/src/projects.rs index a1cae11..5e755c2 100644 --- a/src/projects.rs +++ b/src/projects.rs @@ -5,11 +5,12 @@ use crate::{ widgets::table::Table, }; use serde::Deserialize; -use std::fs; +use std::{fs, path::PathBuf}; #[derive(Debug, PartialEq, Eq)] pub struct Project { pub name: String, + pub root_dir: PathBuf, pub setup: ProjectSetup, } @@ -20,9 +21,9 @@ pub enum ProjectSetup { Windows(Vec), } -impl From for Table { - fn from(value: ProjectSetup) -> Self { - let (template_name, windows) = match value { +impl From for Vec { + fn from(val: ProjectSetup) -> Self { + match val { ProjectSetup::Template(template_name) => { let all_templates = parse_template_config(); let template = all_templates @@ -30,10 +31,20 @@ impl From for Table { .find(|t| t.name == template_name) .unwrap_or_else(|| exit!(1, "Template {} could not be found", template_name)); - (Some(template_name), template.windows) + template.windows } - ProjectSetup::Windows(windows) => (None, windows), + ProjectSetup::Windows(windows) => windows, + } + } +} + +impl From for Table { + fn from(value: ProjectSetup) -> Self { + let template_name = match &value { + ProjectSetup::Template(template_name) => Some(template_name.clone()), + ProjectSetup::Windows(_) => None, }; + let windows: Vec = value.into(); let mut rows = Self::new(vec![( "Template".to_string(), @@ -55,6 +66,7 @@ impl<'de> Deserialize<'de> for Project { #[derive(Deserialize)] struct RawProject { name: String, + root_dir: PathBuf, template: Option, windows: Option>, } @@ -73,6 +85,7 @@ impl<'de> Deserialize<'de> for Project { Ok(Project { name: raw.name, + root_dir: raw.root_dir, setup, }) } @@ -118,6 +131,7 @@ windows: project, Project { name: "OsmApp".to_string(), + root_dir: PathBuf::from("~/GitHub/osmapp"), setup: ProjectSetup::Windows(vec![ Window { name: Some(" Neovim".to_string()), @@ -145,6 +159,7 @@ template: Svelte", project, Project { name: "Dlool".to_string(), + root_dir: PathBuf::from("~/SoftwareDevelopment/web/Dlool/dlool_frontend_v2/"), setup: ProjectSetup::Template("Svelte".to_string()) } ); diff --git a/src/templates.rs b/src/templates.rs index c1fe85a..4c292d7 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -53,12 +53,12 @@ pub fn parse_template_config() -> Vec