Skip to content

Commit

Permalink
Add a start command for projects
Browse files Browse the repository at this point in the history
  • Loading branch information
Dlurak committed Aug 21, 2024
1 parent 9e337bc commit 5eef063
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 55 deletions.
14 changes: 14 additions & 0 deletions src/cli/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct ProjectCli {
pub enum ProjectCommands {
#[command(alias = "ls")]
List(ProjectListArgs),
Start(ProjectStartArgs),
}

#[derive(Debug, Parser)]
Expand All @@ -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,
}
2 changes: 1 addition & 1 deletion src/commands/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
50 changes: 49 additions & 1 deletion src/commands/project.rs
Original file line number Diff line number Diff line change
@@ -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),
}
}

Expand All @@ -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");
}
30 changes: 8 additions & 22 deletions src/commands/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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<u8>) -> 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<PathBuf>,
name: Option<String>,
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()
Expand All @@ -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()
Expand Down
27 changes: 21 additions & 6 deletions src/projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand All @@ -20,20 +21,30 @@ pub enum ProjectSetup {
Windows(Vec<Window>),
}

impl From<ProjectSetup> for Table<String, String> {
fn from(value: ProjectSetup) -> Self {
let (template_name, windows) = match value {
impl From<ProjectSetup> for Vec<Window> {
fn from(val: ProjectSetup) -> Self {
match val {
ProjectSetup::Template(template_name) => {
let all_templates = parse_template_config();
let template = all_templates
.into_iter()
.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<ProjectSetup> for Table<String, String> {
fn from(value: ProjectSetup) -> Self {
let template_name = match &value {
ProjectSetup::Template(template_name) => Some(template_name.clone()),
ProjectSetup::Windows(_) => None,
};
let windows: Vec<Window> = value.into();

let mut rows = Self::new(vec![(
"Template".to_string(),
Expand All @@ -55,6 +66,7 @@ impl<'de> Deserialize<'de> for Project {
#[derive(Deserialize)]
struct RawProject {
name: String,
root_dir: PathBuf,
template: Option<String>,
windows: Option<Vec<Window>>,
}
Expand All @@ -73,6 +85,7 @@ impl<'de> Deserialize<'de> for Project {

Ok(Project {
name: raw.name,
root_dir: raw.root_dir,
setup,
})
}
Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -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())
}
);
Expand Down
6 changes: 3 additions & 3 deletions src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ pub fn parse_template_config() -> Vec<Template> {
.collect()
}

pub fn apply_template<'a>(
pub fn apply_windows<'a>(
tmux: Tmux<'a>,
template: &'a Template,
windows: &'a [Window],
dir: &'a Option<PathBuf>,
) -> Tmux<'a> {
let enumerated = template.windows.iter().enumerate();
let enumerated = windows.iter().enumerate();
enumerated.fold(tmux, |tmux, (window_idx, window)| {
let cmd = build_tmux_command(window_idx, window, dir);

Expand Down
20 changes: 19 additions & 1 deletion src/tmux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,25 @@ macro_rules! conditional_command {
if $condition {
$command.into()
} else {
TmuxCommand::new()
tmux_interface::TmuxCommand::new()
}
};
}

fn private_get_unused_name(name: String, used: Option<u8>) -> 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;
private_get_unused_name(name, Some(next_counter))
} else {
new_name
}
}

pub fn get_unused_name(name: String) -> String {
private_get_unused_name(name, None)
}
27 changes: 6 additions & 21 deletions src/widgets/table.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fmt, iter};
use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Table<T: fmt::Display, U: fmt::Display> {
Expand Down Expand Up @@ -75,9 +75,11 @@ where
.zip(values.iter())
.map(|(key, value)| {
format!(
"│ {} │ {} │",
pad_str(key, ' ', key_width),
pad_str(value, ' ', val_width)
"│ {:<width$} │ {:<val_width$} │",
key,
value,
width = key_width,
val_width = val_width
)
})
.collect();
Expand All @@ -94,20 +96,3 @@ where
)
}
}

fn pad_str<T: Into<String>>(string: T, padder: char, len: usize) -> String {
let string = string.into();
let extra_len = len - string.len();
let pad_str: String = iter::repeat(padder).take(extra_len).collect();
format!("{}{}", string, pad_str)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_pad_str() {
assert_eq!(pad_str("hi", ' ', 5), "hi ".to_string());
}
}

0 comments on commit 5eef063

Please sign in to comment.