parent
050f5f6723
commit
036c123488
13 changed files with 429 additions and 83 deletions
|
@ -1767,6 +1767,88 @@ impl GitPanel {
|
|||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
pub(crate) fn git_init(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let worktrees = self
|
||||
.project
|
||||
.read(cx)
|
||||
.visible_worktrees(cx)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let worktree = if worktrees.len() == 1 {
|
||||
Task::ready(Some(worktrees.first().unwrap().clone()))
|
||||
} else if worktrees.len() == 0 {
|
||||
let result = window.prompt(
|
||||
PromptLevel::Warning,
|
||||
"Unable to initialize a git repository",
|
||||
Some("Open a directory first"),
|
||||
&["Ok"],
|
||||
cx,
|
||||
);
|
||||
cx.background_executor()
|
||||
.spawn(async move {
|
||||
result.await.ok();
|
||||
})
|
||||
.detach();
|
||||
return;
|
||||
} else {
|
||||
let worktree_directories = worktrees
|
||||
.iter()
|
||||
.map(|worktree| worktree.read(cx).abs_path())
|
||||
.map(|worktree_abs_path| {
|
||||
if let Ok(path) = worktree_abs_path.strip_prefix(util::paths::home_dir()) {
|
||||
Path::new("~")
|
||||
.join(path)
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
.into()
|
||||
} else {
|
||||
worktree_abs_path.to_string_lossy().to_string().into()
|
||||
}
|
||||
})
|
||||
.collect_vec();
|
||||
let prompt = picker_prompt::prompt(
|
||||
"Where would you like to initialize this git repository?",
|
||||
worktree_directories,
|
||||
self.workspace.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
cx.spawn(|_, _| async move { prompt.await.map(|ix| worktrees[ix].clone()) })
|
||||
};
|
||||
|
||||
cx.spawn_in(window, |this, mut cx| async move {
|
||||
let worktree = match worktree.await {
|
||||
Some(worktree) => worktree,
|
||||
None => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let Ok(result) = this.update(&mut cx, |this, cx| {
|
||||
let fallback_branch_name = GitPanelSettings::get_global(cx)
|
||||
.fallback_branch_name
|
||||
.clone();
|
||||
this.project.read(cx).git_init(
|
||||
worktree.read(cx).abs_path(),
|
||||
fallback_branch_name,
|
||||
cx,
|
||||
)
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let result = result.await;
|
||||
|
||||
this.update_in(&mut cx, |this, _, cx| match result {
|
||||
Ok(()) => {}
|
||||
Err(e) => this.show_error_toast("init", e, cx),
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub(crate) fn pull(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if !self.can_push_and_pull(cx) {
|
||||
return;
|
||||
|
@ -1971,7 +2053,7 @@ impl GitPanel {
|
|||
cx,
|
||||
)
|
||||
})?
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
Ok(selection.map(|selection| Remote {
|
||||
name: current_remotes[selection].clone(),
|
||||
|
@ -2677,7 +2759,13 @@ impl GitPanel {
|
|||
})
|
||||
}
|
||||
|
||||
fn render_panel_header(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render_panel_header(
|
||||
&self,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<impl IntoElement> {
|
||||
self.active_repository.as_ref()?;
|
||||
|
||||
let text;
|
||||
let action;
|
||||
let tooltip;
|
||||
|
@ -2697,39 +2785,42 @@ impl GitPanel {
|
|||
_ => format!("{} Changes", self.entry_count),
|
||||
};
|
||||
|
||||
self.panel_header_container(window, cx)
|
||||
.px_2()
|
||||
.child(
|
||||
panel_button(change_string)
|
||||
.color(Color::Muted)
|
||||
.tooltip(Tooltip::for_action_title_in(
|
||||
"Open diff",
|
||||
&Diff,
|
||||
&self.focus_handle,
|
||||
))
|
||||
.on_click(|_, _, cx| {
|
||||
cx.defer(|cx| {
|
||||
cx.dispatch_action(&Diff);
|
||||
})
|
||||
}),
|
||||
)
|
||||
.child(div().flex_grow()) // spacer
|
||||
.child(self.render_overflow_menu("overflow_menu"))
|
||||
.child(
|
||||
panel_filled_button(text)
|
||||
.tooltip(Tooltip::for_action_title_in(
|
||||
tooltip,
|
||||
action.as_ref(),
|
||||
&self.focus_handle,
|
||||
))
|
||||
.disabled(self.entry_count == 0)
|
||||
.on_click(move |_, _, cx| {
|
||||
let action = action.boxed_clone();
|
||||
cx.defer(move |cx| {
|
||||
cx.dispatch_action(action.as_ref());
|
||||
})
|
||||
}),
|
||||
)
|
||||
Some(
|
||||
self.panel_header_container(window, cx)
|
||||
.px_2()
|
||||
.child(
|
||||
panel_button(change_string)
|
||||
.color(Color::Muted)
|
||||
.tooltip(Tooltip::for_action_title_in(
|
||||
"Open diff",
|
||||
&Diff,
|
||||
&self.focus_handle,
|
||||
))
|
||||
.on_click(|_, _, cx| {
|
||||
cx.defer(|cx| {
|
||||
cx.dispatch_action(&Diff);
|
||||
})
|
||||
}),
|
||||
)
|
||||
.child(div().flex_grow()) // spacer
|
||||
.child(self.render_overflow_menu("overflow_menu"))
|
||||
.child(div().w_2()) // another spacer
|
||||
.child(
|
||||
panel_filled_button(text)
|
||||
.tooltip(Tooltip::for_action_title_in(
|
||||
tooltip,
|
||||
action.as_ref(),
|
||||
&self.focus_handle,
|
||||
))
|
||||
.disabled(self.entry_count == 0)
|
||||
.on_click(move |_, _, cx| {
|
||||
let action = action.boxed_clone();
|
||||
cx.defer(move |cx| {
|
||||
cx.dispatch_action(action.as_ref());
|
||||
})
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn render_footer(
|
||||
|
@ -2949,12 +3040,29 @@ impl GitPanel {
|
|||
.items_center()
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_3()
|
||||
.child(if self.active_repository.is_some() {
|
||||
"No changes to commit"
|
||||
} else {
|
||||
"No Git repositories"
|
||||
})
|
||||
.gap_2()
|
||||
.child(h_flex().w_full().justify_around().child(
|
||||
if self.active_repository.is_some() {
|
||||
"No changes to commit"
|
||||
} else {
|
||||
"No Git repositories"
|
||||
},
|
||||
))
|
||||
.children(self.active_repository.is_none().then(|| {
|
||||
h_flex().w_full().justify_around().child(
|
||||
panel_filled_button("Initialize Repository")
|
||||
.tooltip(Tooltip::for_action_title_in(
|
||||
"git init",
|
||||
&git::Init,
|
||||
&self.focus_handle,
|
||||
))
|
||||
.on_click(move |_, _, cx| {
|
||||
cx.defer(move |cx| {
|
||||
cx.dispatch_action(&git::Init);
|
||||
})
|
||||
}),
|
||||
)
|
||||
}))
|
||||
.text_ui_sm(cx)
|
||||
.mx_auto()
|
||||
.text_color(Color::Placeholder.color(cx)),
|
||||
|
@ -3674,7 +3782,7 @@ impl Render for GitPanel {
|
|||
.child(
|
||||
v_flex()
|
||||
.size_full()
|
||||
.child(self.render_panel_header(window, cx))
|
||||
.children(self.render_panel_header(window, cx))
|
||||
.map(|this| {
|
||||
if has_entries {
|
||||
this.child(self.render_entries(has_write_access, window, cx))
|
||||
|
|
|
@ -58,15 +58,22 @@ pub struct GitPanelSettingsContent {
|
|||
///
|
||||
/// Default: inherits editor scrollbar settings
|
||||
pub scrollbar: Option<ScrollbarSettings>,
|
||||
|
||||
/// What the default branch name should be when
|
||||
/// `init.defaultBranch` is not set in git
|
||||
///
|
||||
/// Default: main
|
||||
pub fallback_branch_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct GitPanelSettings {
|
||||
pub button: bool,
|
||||
pub dock: DockPosition,
|
||||
pub default_width: Pixels,
|
||||
pub status_style: StatusStyle,
|
||||
pub scrollbar: ScrollbarSettings,
|
||||
pub fallback_branch_name: String,
|
||||
}
|
||||
|
||||
impl Settings for GitPanelSettings {
|
||||
|
|
|
@ -82,6 +82,14 @@ pub fn init(cx: &mut App) {
|
|||
panel.unstage_all(action, window, cx);
|
||||
});
|
||||
});
|
||||
workspace.register_action(|workspace, _action: &git::Init, window, cx| {
|
||||
let Some(panel) = workspace.panel::<git_panel::GitPanel>(cx) else {
|
||||
return;
|
||||
};
|
||||
panel.update(cx, |panel, cx| {
|
||||
panel.git_init(window, cx);
|
||||
});
|
||||
});
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use futures::channel::oneshot;
|
||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
|
||||
|
@ -26,9 +25,9 @@ pub fn prompt(
|
|||
workspace: WeakEntity<Workspace>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Option<usize>>> {
|
||||
) -> Task<Option<usize>> {
|
||||
if options.is_empty() {
|
||||
return Task::ready(Err(anyhow!("No options")));
|
||||
return Task::ready(None);
|
||||
}
|
||||
let prompt = prompt.to_string().into();
|
||||
|
||||
|
@ -37,15 +36,17 @@ pub fn prompt(
|
|||
let (tx, rx) = oneshot::channel();
|
||||
let delegate = PickerPromptDelegate::new(prompt, options, tx, 70);
|
||||
|
||||
workspace.update_in(&mut cx, |workspace, window, cx| {
|
||||
workspace.toggle_modal(window, cx, |window, cx| {
|
||||
PickerPrompt::new(delegate, 34., window, cx)
|
||||
workspace
|
||||
.update_in(&mut cx, |workspace, window, cx| {
|
||||
workspace.toggle_modal(window, cx, |window, cx| {
|
||||
PickerPrompt::new(delegate, 34., window, cx)
|
||||
})
|
||||
})
|
||||
})?;
|
||||
.ok();
|
||||
|
||||
match rx.await {
|
||||
Ok(selection) => Some(selection).transpose(),
|
||||
Err(_) => anyhow::Ok(None), // User cancelled
|
||||
Ok(selection) => Some(selection),
|
||||
Err(_) => None, // User cancelled
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -94,14 +95,14 @@ pub struct PickerPromptDelegate {
|
|||
all_options: Vec<SharedString>,
|
||||
selected_index: usize,
|
||||
max_match_length: usize,
|
||||
tx: Option<oneshot::Sender<Result<usize>>>,
|
||||
tx: Option<oneshot::Sender<usize>>,
|
||||
}
|
||||
|
||||
impl PickerPromptDelegate {
|
||||
pub fn new(
|
||||
prompt: Arc<str>,
|
||||
options: Vec<SharedString>,
|
||||
tx: oneshot::Sender<Result<usize>>,
|
||||
tx: oneshot::Sender<usize>,
|
||||
max_chars: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -200,7 +201,7 @@ impl PickerDelegate for PickerPromptDelegate {
|
|||
return;
|
||||
};
|
||||
|
||||
self.tx.take().map(|tx| tx.send(Ok(option.candidate_id)));
|
||||
self.tx.take().map(|tx| tx.send(option.candidate_id));
|
||||
cx.emit(DismissEvent);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue