Skip to content

Commit 94bbf3c

Browse files
authored
Branch popup (#303)
closes #91
1 parent 92b1b4c commit 94bbf3c

File tree

10 files changed

+449
-8
lines changed

10 files changed

+449
-8
lines changed

assets/vim_style_key_config.ron

+2-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@
6464
log_tag_commit: ( code: Char('t'), modifiers: ( bits: 0,),),
6565
commit_amend: ( code: Char('A'), modifiers: ( bits: 1,),),
6666
copy: ( code: Char('y'), modifiers: ( bits: 0,),),
67-
create_branch: ( code: Char('b'), modifiers: ( bits: 0,),),
67+
create_branch: ( code: Char('c'), modifiers: ( bits: 0,),),
68+
select_branch: ( code: Char('b'), modifiers: ( bits: 0,),),
6869
push: ( code: Char('p'), modifiers: ( bits: 0,),),
6970
fetch: ( code: Char('f'), modifiers: ( bits: 0,),),
7071
)

asyncgit/src/sync/branch.rs

+81
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::{
44
error::{Error, Result},
55
sync::utils,
66
};
7+
use git2::BranchType;
78
use scopetime::scope_time;
89
use utils::get_head_repo;
910

@@ -28,6 +29,86 @@ pub(crate) fn get_branch_name(repo_path: &str) -> Result<String> {
2829
Err(Error::NoHead)
2930
}
3031

32+
///
33+
pub struct BranchForDisplay {
34+
///
35+
pub name: String,
36+
///
37+
pub reference: String,
38+
///
39+
pub top_commit_message: String,
40+
///
41+
pub top_commit_reference: String,
42+
///
43+
pub is_head: bool,
44+
}
45+
46+
/// TODO make this cached
47+
/// Used to return only the nessessary information for displaying a branch
48+
/// rather than an iterator over the actual branches
49+
pub fn get_branches_to_display(
50+
repo_path: &str,
51+
) -> Result<Vec<BranchForDisplay>> {
52+
scope_time!("get_branches_to_display");
53+
let cur_repo = utils::repo(repo_path)?;
54+
let mut branches_for_display = vec![];
55+
56+
for b in cur_repo.branches(Some(BranchType::Local))? {
57+
let branch = &b?.0;
58+
let top_commit = branch.get().peel_to_commit()?;
59+
let mut commit_id = top_commit.id().to_string();
60+
commit_id.truncate(7);
61+
62+
branches_for_display.push(BranchForDisplay {
63+
name: String::from_utf8(Vec::from(branch.name_bytes()?))?,
64+
reference: String::from_utf8(Vec::from(
65+
branch.get().name_bytes(),
66+
))?,
67+
top_commit_message: String::from_utf8(Vec::from(
68+
top_commit.summary_bytes().unwrap_or(&[]),
69+
))?,
70+
top_commit_reference: commit_id,
71+
is_head: branch.is_head(),
72+
})
73+
}
74+
Ok(branches_for_display)
75+
}
76+
77+
/// Modify HEAD to point to a branch then checkout head, does not work if there are uncommitted changes
78+
pub fn checkout_branch(
79+
repo_path: &str,
80+
branch_ref: &str,
81+
) -> Result<()> {
82+
scope_time!("checkout_branch");
83+
// This defaults to a safe checkout, so don't delete anything that
84+
// hasn't been committed or stashed, in this case it will Err
85+
let repo = utils::repo(repo_path)?;
86+
let cur_ref = repo.head()?;
87+
if repo
88+
.statuses(Some(
89+
git2::StatusOptions::new().include_ignored(false),
90+
))?
91+
.is_empty()
92+
{
93+
repo.set_head(branch_ref)?;
94+
95+
if let Err(e) = repo.checkout_head(Some(
96+
git2::build::CheckoutBuilder::new().force(),
97+
)) {
98+
// This is safe beacuse cur_ref was just found
99+
repo.set_head(cur_ref.name().unwrap_or(""))?;
100+
return Err(Error::Git(e));
101+
}
102+
Ok(())
103+
} else {
104+
Err(Error::Generic(
105+
format!("Cannot change branch. There are unstaged/staged changes which have not been committed/stashed. There is {:?} changes preventing checking out a different branch.", repo.statuses(Some(
106+
git2::StatusOptions::new().include_ignored(false),
107+
))?.len()),
108+
))
109+
}
110+
}
111+
31112
/// creates a new branch pointing to current HEAD commit and updating HEAD to new branch
32113
pub fn create_branch(repo_path: &str, name: &str) -> Result<()> {
33114
scope_time!("create_branch");

asyncgit/src/sync/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ pub mod status;
1717
mod tags;
1818
pub mod utils;
1919

20-
pub use branch::create_branch;
2120
pub(crate) use branch::get_branch_name;
21+
pub use branch::{
22+
checkout_branch, create_branch, get_branches_to_display,
23+
BranchForDisplay,
24+
};
2225
pub use commit::{amend, commit, tag};
2326
pub use commit_details::{
2427
get_commit_details, CommitDetails, CommitMessage,

src/app.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use crate::{
66
Component, CreateBranchComponent, DrawableComponent,
77
ExternalEditorComponent, HelpComponent,
88
InspectCommitComponent, MsgComponent, PushComponent,
9-
ResetComponent, StashMsgComponent, TagCommitComponent,
9+
ResetComponent, SelectBranchComponent, StashMsgComponent,
10+
TagCommitComponent,
1011
},
1112
input::{Input, InputEvent, InputState},
1213
keys::{KeyConfig, SharedKeyConfig},
@@ -45,6 +46,7 @@ pub struct App {
4546
push_popup: PushComponent,
4647
tag_commit_popup: TagCommitComponent,
4748
create_branch_popup: CreateBranchComponent,
49+
select_branch_popup: SelectBranchComponent,
4850
cmdbar: RefCell<CommandBar>,
4951
tab: usize,
5052
revlog: Revlog,
@@ -116,6 +118,11 @@ impl App {
116118
theme.clone(),
117119
key_config.clone(),
118120
),
121+
select_branch_popup: SelectBranchComponent::new(
122+
queue.clone(),
123+
theme.clone(),
124+
key_config.clone(),
125+
),
119126
do_quit: false,
120127
cmdbar: RefCell::new(CommandBar::new(
121128
theme.clone(),
@@ -335,6 +342,7 @@ impl App {
335342
push_popup,
336343
tag_commit_popup,
337344
create_branch_popup,
345+
select_branch_popup,
338346
help,
339347
revlog,
340348
status_tab,
@@ -487,6 +495,9 @@ impl App {
487495
InternalEvent::CreateBranch => {
488496
self.create_branch_popup.open()?;
489497
}
498+
InternalEvent::SelectBranch => {
499+
self.select_branch_popup.open()?;
500+
}
490501
InternalEvent::TabSwitch => self.set_tab(0)?,
491502
InternalEvent::InspectCommit(id, tags) => {
492503
self.inspect_commit_popup.open(id, tags)?;
@@ -562,6 +573,7 @@ impl App {
562573
|| self.tag_commit_popup.is_visible()
563574
|| self.create_branch_popup.is_visible()
564575
|| self.push_popup.is_visible()
576+
|| self.select_branch_popup.is_visible()
565577
}
566578

567579
fn draw_popups<B: Backend>(
@@ -587,6 +599,7 @@ impl App {
587599
self.msg.draw(f, size)?;
588600
self.external_editor_popup.draw(f, size)?;
589601
self.tag_commit_popup.draw(f, size)?;
602+
self.select_branch_popup.draw(f, size)?;
590603
self.create_branch_popup.draw(f, size)?;
591604
self.push_popup.draw(f, size)?;
592605

src/components/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod inspect_commit;
1212
mod msg;
1313
mod push;
1414
mod reset;
15+
mod select_branch;
1516
mod stashmsg;
1617
mod tag_commit;
1718
mod textinput;
@@ -34,6 +35,7 @@ pub use inspect_commit::InspectCommitComponent;
3435
pub use msg::MsgComponent;
3536
pub use push::PushComponent;
3637
pub use reset::ResetComponent;
38+
pub use select_branch::SelectBranchComponent;
3739
pub use stashmsg::StashMsgComponent;
3840
pub use tag_commit::TagCommitComponent;
3941
pub use textinput::TextInputComponent;

0 commit comments

Comments
 (0)