pcode-cli/src/lib.rs

271 lines
10 KiB
Rust

mod cli;
mod config;
mod core;
mod misc;
mod notes;
mod projects;
mod templates;
mod timer;
use clap::Parser;
use strfmt::strfmt;
use std::collections::HashMap;
use std::{fs, process};
use cli::{CLI, Commands, NotesAction, PomodoroAction, ProjectsAction, TemplateAction};
use config::{Config, load_config, save_config};
use projects::{commits_info, repository_status};
use templates::{list_templates, load_template};
use timer::run_timer;
fn parse_config() -> Config {
let cfg: Config = match load_config() {
Ok(cfg) => cfg,
Err(err) => {
eprintln!("Configuration error:\n{}", err);
process::exit(1);
}
};
cfg
}
fn process_command(mut cfg: Config) {
let cli = CLI::parse();
match cli.command {
Some(Commands::Template(template_command)) => match template_command.action {
TemplateAction::List => {
let templates = match list_templates(&cfg.templates_dir) {
Ok(temps) => temps,
Err(err) => {
eprintln!("Error scanning template list:\n{}", err);
process::exit(1);
}
};
// TODO: Add grouping by language.
for template in templates {
eprintln!("{} >- {}", template.language, template.name);
}
}
TemplateAction::Load { name, vars } => match load_template(&cfg.templates_dir, &name) {
Ok(_) => {
eprintln!("Template succesfully copied!");
eprintln!("Vars: {:?}", vars);
}
Err(err) => {
eprintln!("Error while loading template:\n{}", err);
process::exit(1)
}
},
},
Some(Commands::Timer(timer_command)) => match timer_command.action {
PomodoroAction::Start => {
match run_timer(cfg.timer_concentrate_mins, cfg.timer_rest_mins) {
Ok(_) => {}
Err(err) => {
eprintln!("Error while running timer:\n{}", err);
process::exit(1);
}
};
}
PomodoroAction::Set { concentrate, rest } => {
let mut concentrate_updated: bool = false;
let mut rest_updated: bool = false;
match concentrate {
Some(mins) => {
cfg.timer_concentrate_mins = mins;
concentrate_updated = true;
}
_ => {}
}
match rest {
Some(mins) => {
cfg.timer_rest_mins = mins;
rest_updated = true;
}
_ => {}
}
match save_config(&cfg) {
Ok(_) => {
if concentrate_updated {
eprintln!(
"Successfully update concentrate mins: {}",
concentrate.unwrap()
);
}
if rest_updated {
eprintln!("Successfully update rest mins: {}", rest.unwrap());
}
if !concentrate_updated && !rest_updated {
eprintln!("Error: you need to set 1 argument <concentrate/rest>");
process::exit(1);
}
}
Err(err) => {
eprintln!("Get error while saving config:\n{}", err);
process::exit(1);
}
};
}
},
Some(Commands::Project(project_action)) => match project_action.action {
ProjectsAction::Add { path } => {
let path = match fs::canonicalize(path) {
Ok(p) => p,
Err(err) => {
eprintln!("Error:\n{}", err);
process::exit(1);
}
};
if let None = path.file_name() {
eprintln!("Error:\nproject folder/file empty name.");
process::exit(1);
}
if cfg.projects.contains(&path) {
eprintln!("Project already added.");
process::exit(1);
}
cfg.projects.push(path.clone());
match save_config(&cfg) {
Ok(_) => {
eprintln!("Successfully add path: {}", path.display());
}
Err(err) => {
eprintln!("Get error while saving config:\n{}", err);
process::exit(1);
}
}
}
ProjectsAction::Remove { project_name } => {
let mut is_deleted = false;
for (idx, project) in cfg.projects.iter().enumerate() {
match project.file_name() {
Some(name) => {
if String::from(name.to_str().unwrap()) == project_name {
cfg.projects.remove(idx);
is_deleted = true;
break;
}
}
None => eprintln!(
"Error: project folder/file empty name '{}'",
project.display()
),
}
}
if !is_deleted {
eprintln!("Can't find project with name '{}'", project_name);
process::exit(1);
}
match save_config(&cfg) {
Ok(_) => {
eprintln!("Successfully remove project: {}", project_name);
}
Err(err) => {
eprintln!("Get error while saving config:\n{}", err);
process::exit(1);
}
}
}
ProjectsAction::List => {
eprintln!("Projects:");
for project in cfg.projects {
match project.file_name() {
Some(name) => {
if let Ok(commits_info) = commits_info(project.clone())
&& let Ok(repo_status) = repository_status(project.clone())
{
let mut template = String::new();
template.push_str("{project_name}: {last_change_info}\n\t");
template.push_str("commits: {commits_cnt}\n\t");
template.push_str("last update: {updated_date}\n\t");
template.push_str("current branch: {current_branch}\n\t");
template.push_str("uncommited changes: {is_dirty}\n\t");
template.push_str("upstream: {upstream_name}\n\t");
template.push_str("unpushed changes: {has_unpushed}\n\t");
template.push_str("\n");
let mut vars = HashMap::new();
vars.insert("project_name".to_string(), name.display().to_string());
vars.insert(
"last_change_info".to_string(),
commits_info.render_last_change_info(),
);
vars.insert(
"commits_cnt".to_string(),
commits_info.cnt.to_string(),
);
vars.insert(
"updated_date".to_string(),
commits_info.render_updated_date(),
);
vars.insert("current_branch".to_string(), repo_status.branch_name);
vars.insert(
"is_dirty".to_string(),
repo_status.is_dirty.to_string(),
);
vars.insert(
"upstream_name".to_string(),
repo_status.upstream_name.unwrap_or("None".to_string()),
);
vars.insert(
"has_unpushed".to_string(),
if let Some(st) = repo_status.has_unpushed {
st.to_string()
} else {
"None".to_string()
},
);
let rendered = strfmt(&template, &vars).unwrap();
eprint!("{}", rendered);
} else {
eprintln!("{}: can't get info", name.display());
};
}
None => eprintln!(
"Error: project folder/file empty name '{}'",
project.display()
),
}
}
}
},
Some(Commands::Notes(notes_command)) => match notes_command.action {
NotesAction::Add => {
todo!("Add notes!");
}
NotesAction::Remove => {
todo!("Remove notes!");
}
NotesAction::List => {
todo!("List of notes!");
// let notes = cfg.notes;
}
},
None => {
eprintln!("No command provided. Use --help for usage.");
process::exit(1);
}
}
}
pub fn run() {
let cfg = parse_config();
process_command(cfg);
}