1use std::{
2 env,
3 io::{stdout, Write},
4};
5
6pub use commands::*;
7use menu::{run_menu, Menu};
8use repo::{checkout, current_branch, get_branches, root_repo_path, Branch};
9
10mod commands;
11mod config;
12mod menu;
13mod repo;
14mod util;
15
16pub fn help(version: &str) {
17 println!("git-switch-branch v{}", version);
18 println!("Usage: git-switch-branch [options]");
19 println!(" help Show this help message");
20 println!(" version Show the version number");
21 println!("");
22 println!(" r, remote Show only remote branches");
23 println!(" a, all Show all branches (local and remote)");
24 println!("");
25 println!(" alias add Add a git alias for this command");
26 println!(" alias remove Remove the git alias (if set)");
27 println!(" alias Show the current alias");
28}
29
30pub fn list_alias() {
31 let alias = config::get_current_alias().unwrap_or_else(|_| fatal!("Could not read alias file"));
32
33 match alias {
34 Some(alias) => println!("{}", alias),
35 None => println!("No alias set"),
36 }
37}
38
39pub fn add_alias() {
40 let alias = config::get_current_alias().unwrap_or_else(|_| fatal!("Could not read alias file"));
41
42 if alias.is_some() {
43 println!("Current alias: {}", alias.as_ref().unwrap());
44 }
45
46 let mut input = String::new();
47
48 let new_alias = loop {
49 print!("Enter new alias: ");
50 stdout().flush().unwrap();
51
52 let stdin = std::io::stdin();
53 stdin.read_line(&mut input).unwrap();
54 let alias = input.trim();
55
56 if alias.is_empty() {
57 println!("Alias cannot be empty");
58 input.clear();
59 continue;
60 }
61
62 break alias;
63 };
64
65 config::update_alias(new_alias, alias.as_deref())
66 .unwrap_or_else(|_| fatal!("Could not update alias"));
67
68 println!("Alias updated");
69}
70
71pub fn remove_alias() {
72 let alias = config::get_current_alias().unwrap_or_else(|_| fatal!("Could not read alias file"));
73 if alias.is_none() {
74 println!("No alias set");
75 return;
76 }
77
78 config::remove_alias(alias.as_deref()).unwrap_or_else(|_| fatal!("Could not remove alias"));
79 println!("Alias removed");
80}
81
82pub fn switch_branch(local: bool, remote: bool) {
83 let repo_path = env::current_dir()
84 .map(|mut path| root_repo_path(&mut path))
85 .expect("Can't access current directory")
86 .unwrap_or_else(|| fatal!("Could not find git repository"));
87
88 let branches = get_branches(&repo_path, local, remote)
89 .unwrap_or_else(|_| fatal!("Could not read branches"));
90
91 let current_branch = current_branch(&repo_path)
92 .map(|res| branches.iter().position(|branch| branch.to_string() == res))
93 .unwrap_or_default();
94
95 if branches.len() == 0 {
96 println!("No branches found");
97 return;
98 }
99
100 let menu = Menu {
101 items: &branches,
102 current: current_branch,
103 ..Default::default()
104 };
105
106 let selected = run_menu(&menu).map(|i| &branches[i]).unwrap_or_else(|err| {
107 fatal!("Could not run menu: {}", err);
108 });
109
110 let branch = match &selected {
111 Branch::Remote(_, branch) => {
112 let opts = vec![
113 format!("Create local branch '{}'", branch),
114 "Checkout remote branch (detached HEAD)".to_owned(),
115 ];
116 let menu = Menu {
117 items: &opts,
118 ..Default::default()
119 };
120
121 let opt = run_menu(&menu).unwrap_or_else(|err| fatal!("Could not run menu: {}", err));
122
123 match opt {
124 0 => branch,
125 _ => &selected.to_string(),
126 }
127 }
128 Branch::Local(branch) => branch,
129 };
130
131 checkout(branch).unwrap_or_else(|_| fatal!("Could not checkout branch"));
132}