mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 08:58:21 +00:00
Rename branch (#334)
This commit is contained in:
parent
9297915ddd
commit
71880f96f7
10 changed files with 301 additions and 3 deletions
|
|
@ -65,6 +65,7 @@
|
|||
commit_amend: ( code: Char('A'), modifiers: ( bits: 1,),),
|
||||
copy: ( code: Char('y'), modifiers: ( bits: 0,),),
|
||||
create_branch: ( code: Char('c'), modifiers: ( bits: 0,),),
|
||||
rename_branch: ( code: Char('r'), modifiers: ( bits: 0,),),
|
||||
select_branch: ( code: Char('b'), modifiers: ( bits: 0,),),
|
||||
delete_branch: ( code: Char('D'), modifiers: ( bits: 1,),),
|
||||
push: ( code: Char('p'), modifiers: ( bits: 0,),),
|
||||
|
|
|
|||
|
|
@ -130,6 +130,22 @@ pub fn delete_branch(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Rename the branch reference
|
||||
pub fn rename_branch(
|
||||
repo_path: &str,
|
||||
branch_ref: &str,
|
||||
new_name: &str,
|
||||
) -> Result<()> {
|
||||
scope_time!("delete_branch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let branch_as_ref = repo.find_reference(branch_ref)?;
|
||||
let mut branch = git2::Branch::wrap(branch_as_ref);
|
||||
branch.rename(new_name, true)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// creates a new branch pointing to current HEAD commit and updating HEAD to new branch
|
||||
pub fn create_branch(repo_path: &str, name: &str) -> Result<()> {
|
||||
scope_time!("create_branch");
|
||||
|
|
@ -318,3 +334,49 @@ mod test_delete_branch {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_rename_branch {
|
||||
use super::*;
|
||||
use crate::sync::tests::repo_init;
|
||||
|
||||
#[test]
|
||||
fn test_rename_branch() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
|
||||
create_branch(repo_path, "branch1").unwrap();
|
||||
|
||||
checkout_branch(repo_path, "refs/heads/branch1").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
repo.branches(None)
|
||||
.unwrap()
|
||||
.nth(0)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.0
|
||||
.name()
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
"branch1"
|
||||
);
|
||||
|
||||
rename_branch(repo_path, "refs/heads/branch1", "AnotherName")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
repo.branches(None)
|
||||
.unwrap()
|
||||
.nth(0)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.0
|
||||
.name()
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
"AnotherName"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pub mod utils;
|
|||
pub(crate) use branch::get_branch_name;
|
||||
pub use branch::{
|
||||
checkout_branch, create_branch, delete_branch,
|
||||
get_branches_to_display, BranchForDisplay,
|
||||
get_branches_to_display, rename_branch, BranchForDisplay,
|
||||
};
|
||||
pub use commit::{amend, commit, tag};
|
||||
pub use commit_details::{
|
||||
|
|
|
|||
17
src/app.rs
17
src/app.rs
|
|
@ -6,8 +6,8 @@ use crate::{
|
|||
Component, CreateBranchComponent, DrawableComponent,
|
||||
ExternalEditorComponent, HelpComponent,
|
||||
InspectCommitComponent, MsgComponent, PushComponent,
|
||||
ResetComponent, SelectBranchComponent, StashMsgComponent,
|
||||
TagCommitComponent,
|
||||
RenameBranchComponent, ResetComponent, SelectBranchComponent,
|
||||
StashMsgComponent, TagCommitComponent,
|
||||
},
|
||||
input::{Input, InputEvent, InputState},
|
||||
keys::{KeyConfig, SharedKeyConfig},
|
||||
|
|
@ -46,6 +46,7 @@ pub struct App {
|
|||
push_popup: PushComponent,
|
||||
tag_commit_popup: TagCommitComponent,
|
||||
create_branch_popup: CreateBranchComponent,
|
||||
rename_branch_popup: RenameBranchComponent,
|
||||
select_branch_popup: SelectBranchComponent,
|
||||
cmdbar: RefCell<CommandBar>,
|
||||
tab: usize,
|
||||
|
|
@ -118,6 +119,11 @@ impl App {
|
|||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
rename_branch_popup: RenameBranchComponent::new(
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
select_branch_popup: SelectBranchComponent::new(
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
|
|
@ -342,6 +348,7 @@ impl App {
|
|||
push_popup,
|
||||
tag_commit_popup,
|
||||
create_branch_popup,
|
||||
rename_branch_popup,
|
||||
select_branch_popup,
|
||||
help,
|
||||
revlog,
|
||||
|
|
@ -509,6 +516,10 @@ impl App {
|
|||
InternalEvent::CreateBranch => {
|
||||
self.create_branch_popup.open()?;
|
||||
}
|
||||
InternalEvent::RenameBranch(branch_ref, cur_name) => {
|
||||
self.rename_branch_popup
|
||||
.open(branch_ref, cur_name)?;
|
||||
}
|
||||
InternalEvent::SelectBranch => {
|
||||
self.select_branch_popup.open()?;
|
||||
}
|
||||
|
|
@ -588,6 +599,7 @@ impl App {
|
|||
|| self.create_branch_popup.is_visible()
|
||||
|| self.push_popup.is_visible()
|
||||
|| self.select_branch_popup.is_visible()
|
||||
|| self.rename_branch_popup.is_visible()
|
||||
}
|
||||
|
||||
fn draw_popups<B: Backend>(
|
||||
|
|
@ -613,6 +625,7 @@ impl App {
|
|||
self.tag_commit_popup.draw(f, size)?;
|
||||
self.select_branch_popup.draw(f, size)?;
|
||||
self.create_branch_popup.draw(f, size)?;
|
||||
self.rename_branch_popup.draw(f, size)?;
|
||||
self.push_popup.draw(f, size)?;
|
||||
self.reset.draw(f, size)?;
|
||||
self.msg.draw(f, size)?;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ mod help;
|
|||
mod inspect_commit;
|
||||
mod msg;
|
||||
mod push;
|
||||
mod rename_branch;
|
||||
mod reset;
|
||||
mod select_branch;
|
||||
mod stashmsg;
|
||||
|
|
@ -34,6 +35,7 @@ pub use help::HelpComponent;
|
|||
pub use inspect_commit::InspectCommitComponent;
|
||||
pub use msg::MsgComponent;
|
||||
pub use push::PushComponent;
|
||||
pub use rename_branch::RenameBranchComponent;
|
||||
pub use reset::ResetComponent;
|
||||
pub use select_branch::SelectBranchComponent;
|
||||
pub use stashmsg::StashMsgComponent;
|
||||
|
|
|
|||
166
src/components/rename_branch.rs
Normal file
166
src/components/rename_branch.rs
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
use super::{
|
||||
textinput::TextInputComponent, visibility_blocking,
|
||||
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
||||
};
|
||||
use crate::{
|
||||
keys::SharedKeyConfig,
|
||||
queue::{InternalEvent, NeedsUpdate, Queue},
|
||||
strings,
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self},
|
||||
CWD,
|
||||
};
|
||||
use crossterm::event::Event;
|
||||
use tui::{backend::Backend, layout::Rect, Frame};
|
||||
|
||||
pub struct RenameBranchComponent {
|
||||
input: TextInputComponent,
|
||||
branch_ref: Option<String>,
|
||||
queue: Queue,
|
||||
key_config: SharedKeyConfig,
|
||||
}
|
||||
|
||||
impl DrawableComponent for RenameBranchComponent {
|
||||
fn draw<B: Backend>(
|
||||
&self,
|
||||
f: &mut Frame<B>,
|
||||
rect: Rect,
|
||||
) -> Result<()> {
|
||||
self.input.draw(f, rect)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for RenameBranchComponent {
|
||||
fn commands(
|
||||
&self,
|
||||
out: &mut Vec<CommandInfo>,
|
||||
force_all: bool,
|
||||
) -> CommandBlocking {
|
||||
if self.is_visible() || force_all {
|
||||
self.input.commands(out, force_all);
|
||||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::rename_branch_confirm_msg(
|
||||
&self.key_config,
|
||||
),
|
||||
true,
|
||||
true,
|
||||
));
|
||||
}
|
||||
|
||||
visibility_blocking(self)
|
||||
}
|
||||
|
||||
fn event(&mut self, ev: Event) -> Result<bool> {
|
||||
if self.is_visible() {
|
||||
if self.input.event(ev)? {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Event::Key(e) = ev {
|
||||
if e == self.key_config.enter {
|
||||
self.rename_branch();
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn is_visible(&self) -> bool {
|
||||
self.input.is_visible()
|
||||
}
|
||||
|
||||
fn hide(&mut self) {
|
||||
self.input.hide()
|
||||
}
|
||||
|
||||
fn show(&mut self) -> Result<()> {
|
||||
self.input.show()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl RenameBranchComponent {
|
||||
///
|
||||
pub fn new(
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
queue,
|
||||
input: TextInputComponent::new(
|
||||
theme,
|
||||
key_config.clone(),
|
||||
&strings::rename_branch_popup_title(&key_config),
|
||||
&strings::rename_branch_popup_msg(&key_config),
|
||||
),
|
||||
branch_ref: None,
|
||||
key_config,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn open(
|
||||
&mut self,
|
||||
branch_ref: String,
|
||||
cur_name: String,
|
||||
) -> Result<()> {
|
||||
self.branch_ref = None;
|
||||
self.branch_ref = Some(branch_ref);
|
||||
self.input.set_text(cur_name);
|
||||
self.show()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
pub fn rename_branch(&mut self) {
|
||||
if let Some(br) = &self.branch_ref {
|
||||
let res = sync::rename_branch(
|
||||
CWD,
|
||||
br,
|
||||
self.input.get_text().as_str(),
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(_) => {
|
||||
self.queue.borrow_mut().push_back(
|
||||
InternalEvent::Update(NeedsUpdate::ALL),
|
||||
);
|
||||
self.hide();
|
||||
self.queue
|
||||
.borrow_mut()
|
||||
.push_back(InternalEvent::SelectBranch);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("create branch: {}", e,);
|
||||
self.queue.borrow_mut().push_back(
|
||||
InternalEvent::ShowErrorMsg(format!(
|
||||
"rename branch error:\n{}",
|
||||
e,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::error!("create branch: No branch selected");
|
||||
self.queue
|
||||
.borrow_mut()
|
||||
.push_back(InternalEvent::ShowErrorMsg(
|
||||
"rename branch error: No branch selected to rename"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
self.input.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -121,6 +121,14 @@ impl Component for SelectBranchComponent {
|
|||
!self.selection_is_cur_branch(),
|
||||
true,
|
||||
));
|
||||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::rename_branch_popup(
|
||||
&self.key_config,
|
||||
),
|
||||
true,
|
||||
true,
|
||||
));
|
||||
}
|
||||
visibility_blocking(self)
|
||||
}
|
||||
|
|
@ -150,6 +158,16 @@ impl Component for SelectBranchComponent {
|
|||
.borrow_mut()
|
||||
.push_back(InternalEvent::CreateBranch);
|
||||
self.hide();
|
||||
} else if e == self.key_config.rename_branch {
|
||||
let cur_branch =
|
||||
&self.branch_names[self.selection as usize];
|
||||
self.queue.borrow_mut().push_back(
|
||||
InternalEvent::RenameBranch(
|
||||
cur_branch.reference.clone(),
|
||||
cur_branch.name.clone(),
|
||||
),
|
||||
);
|
||||
self.hide();
|
||||
} else if e == self.key_config.delete_branch
|
||||
&& !self.selection_is_cur_branch()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ pub struct KeyConfig {
|
|||
pub commit_amend: KeyEvent,
|
||||
pub copy: KeyEvent,
|
||||
pub create_branch: KeyEvent,
|
||||
pub rename_branch: KeyEvent,
|
||||
pub select_branch: KeyEvent,
|
||||
pub delete_branch: KeyEvent,
|
||||
pub push: KeyEvent,
|
||||
|
|
@ -113,6 +114,7 @@ impl Default for KeyConfig {
|
|||
commit_amend: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::CONTROL},
|
||||
copy: KeyEvent { code: KeyCode::Char('y'), modifiers: KeyModifiers::empty()},
|
||||
create_branch: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::NONE},
|
||||
rename_branch: KeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::NONE},
|
||||
select_branch: KeyEvent { code: KeyCode::Char('b'), modifiers: KeyModifiers::NONE},
|
||||
delete_branch: KeyEvent{code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT},
|
||||
push: KeyEvent { code: KeyCode::Char('p'), modifiers: KeyModifiers::empty()},
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ pub enum InternalEvent {
|
|||
///
|
||||
CreateBranch,
|
||||
///
|
||||
RenameBranch(String, String),
|
||||
///
|
||||
SelectBranch,
|
||||
///
|
||||
OpenExternalEditor(Option<String>),
|
||||
|
|
|
|||
|
|
@ -140,6 +140,17 @@ pub fn create_branch_popup_msg(
|
|||
"type branch name".to_string()
|
||||
}
|
||||
|
||||
pub fn rename_branch_popup_title(
|
||||
_key_config: &SharedKeyConfig,
|
||||
) -> String {
|
||||
"Rename Branch".to_string()
|
||||
}
|
||||
pub fn rename_branch_popup_msg(
|
||||
_key_config: &SharedKeyConfig,
|
||||
) -> String {
|
||||
"new branch name".to_string()
|
||||
}
|
||||
|
||||
pub mod commit {
|
||||
use crate::keys::SharedKeyConfig;
|
||||
pub fn details_author(_key_config: &SharedKeyConfig) -> String {
|
||||
|
|
@ -615,6 +626,27 @@ pub mod commands {
|
|||
CMD_GROUP_GENERAL,
|
||||
)
|
||||
}
|
||||
pub fn rename_branch_confirm_msg(
|
||||
key_config: &SharedKeyConfig,
|
||||
) -> CommandText {
|
||||
CommandText::new(
|
||||
format!("Rename Branch [{}]", get_hint(key_config.enter),),
|
||||
"rename branch",
|
||||
CMD_GROUP_GENERAL,
|
||||
)
|
||||
}
|
||||
pub fn rename_branch_popup(
|
||||
key_config: &SharedKeyConfig,
|
||||
) -> CommandText {
|
||||
CommandText::new(
|
||||
format!(
|
||||
"Rename Branch [{}]",
|
||||
get_hint(key_config.rename_branch),
|
||||
),
|
||||
"rename branch",
|
||||
CMD_GROUP_GENERAL,
|
||||
)
|
||||
}
|
||||
pub fn delete_branch_popup(
|
||||
key_config: &SharedKeyConfig,
|
||||
) -> CommandText {
|
||||
|
|
|
|||
Loading…
Reference in a new issue