Git Panel: separate new and changed (#24181)
Release Notes: - N/A --------- Co-authored-by: conrad <conrad@zed.dev> Co-authored-by: nate <nate@zed.dev>
This commit is contained in:
parent
6659aea13b
commit
71f2cbe798
7 changed files with 666 additions and 589 deletions
|
@ -153,6 +153,7 @@ impl FileStatus {
|
||||||
(StatusCode::Added, _) | (_, StatusCode::Added) => true,
|
(StatusCode::Added, _) | (_, StatusCode::Added) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
FileStatus::Untracked => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,8 +2,8 @@ use crate::worktree_store::{WorktreeStore, WorktreeStoreEvent};
|
||||||
use crate::{Project, ProjectPath};
|
use crate::{Project, ProjectPath};
|
||||||
use anyhow::{anyhow, Context as _};
|
use anyhow::{anyhow, Context as _};
|
||||||
use client::ProjectId;
|
use client::ProjectId;
|
||||||
use futures::channel::mpsc;
|
use futures::channel::{mpsc, oneshot};
|
||||||
use futures::{SinkExt as _, StreamExt as _};
|
use futures::StreamExt as _;
|
||||||
use git::{
|
use git::{
|
||||||
repository::{GitRepository, RepoPath},
|
repository::{GitRepository, RepoPath},
|
||||||
status::{GitSummary, TrackedSummary},
|
status::{GitSummary, TrackedSummary},
|
||||||
|
@ -20,7 +20,7 @@ pub struct GitState {
|
||||||
client: Option<AnyProtoClient>,
|
client: Option<AnyProtoClient>,
|
||||||
repositories: Vec<RepositoryHandle>,
|
repositories: Vec<RepositoryHandle>,
|
||||||
active_index: Option<usize>,
|
active_index: Option<usize>,
|
||||||
update_sender: mpsc::UnboundedSender<(Message, mpsc::Sender<anyhow::Error>)>,
|
update_sender: mpsc::UnboundedSender<(Message, oneshot::Sender<anyhow::Result<()>>)>,
|
||||||
_subscription: Subscription,
|
_subscription: Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ pub struct RepositoryHandle {
|
||||||
pub worktree_id: WorktreeId,
|
pub worktree_id: WorktreeId,
|
||||||
pub repository_entry: RepositoryEntry,
|
pub repository_entry: RepositoryEntry,
|
||||||
pub git_repo: GitRepo,
|
pub git_repo: GitRepo,
|
||||||
update_sender: mpsc::UnboundedSender<(Message, mpsc::Sender<anyhow::Error>)>,
|
update_sender: mpsc::UnboundedSender<(Message, oneshot::Sender<anyhow::Result<()>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -61,11 +61,6 @@ impl PartialEq<RepositoryEntry> for RepositoryHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Message {
|
enum Message {
|
||||||
StageAndCommit {
|
|
||||||
git_repo: GitRepo,
|
|
||||||
paths: Vec<RepoPath>,
|
|
||||||
name_and_email: Option<(SharedString, SharedString)>,
|
|
||||||
},
|
|
||||||
Commit {
|
Commit {
|
||||||
git_repo: GitRepo,
|
git_repo: GitRepo,
|
||||||
name_and_email: Option<(SharedString, SharedString)>,
|
name_and_email: Option<(SharedString, SharedString)>,
|
||||||
|
@ -87,151 +82,7 @@ impl GitState {
|
||||||
project_id: Option<ProjectId>,
|
project_id: Option<ProjectId>,
|
||||||
cx: &mut Context<'_, Self>,
|
cx: &mut Context<'_, Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (update_sender, mut update_receiver) =
|
let update_sender = Self::spawn_git_worker(cx);
|
||||||
mpsc::unbounded::<(Message, mpsc::Sender<anyhow::Error>)>();
|
|
||||||
cx.spawn(|_, cx| async move {
|
|
||||||
while let Some((msg, mut err_sender)) = update_receiver.next().await {
|
|
||||||
let result =
|
|
||||||
cx.background_executor()
|
|
||||||
.spawn(async move {
|
|
||||||
match msg {
|
|
||||||
Message::StageAndCommit {
|
|
||||||
git_repo,
|
|
||||||
name_and_email,
|
|
||||||
paths,
|
|
||||||
} => {
|
|
||||||
match git_repo {
|
|
||||||
GitRepo::Local(repo) => {
|
|
||||||
repo.stage_paths(&paths)?;
|
|
||||||
repo.commit(name_and_email.as_ref().map(
|
|
||||||
|(name, email)| (name.as_ref(), email.as_ref()),
|
|
||||||
))?;
|
|
||||||
}
|
|
||||||
GitRepo::Remote {
|
|
||||||
project_id,
|
|
||||||
client,
|
|
||||||
worktree_id,
|
|
||||||
work_directory_id,
|
|
||||||
} => {
|
|
||||||
client
|
|
||||||
.request(proto::Stage {
|
|
||||||
project_id: project_id.0,
|
|
||||||
worktree_id: worktree_id.to_proto(),
|
|
||||||
work_directory_id: work_directory_id.to_proto(),
|
|
||||||
paths: paths
|
|
||||||
.into_iter()
|
|
||||||
.map(|repo_path| repo_path.to_proto())
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.context("sending stage request")?;
|
|
||||||
let (name, email) = name_and_email.unzip();
|
|
||||||
client
|
|
||||||
.request(proto::Commit {
|
|
||||||
project_id: project_id.0,
|
|
||||||
worktree_id: worktree_id.to_proto(),
|
|
||||||
work_directory_id: work_directory_id.to_proto(),
|
|
||||||
name: name.map(String::from),
|
|
||||||
email: email.map(String::from),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.context("sending commit request")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Message::Stage(repo, paths) => {
|
|
||||||
match repo {
|
|
||||||
GitRepo::Local(repo) => repo.stage_paths(&paths)?,
|
|
||||||
GitRepo::Remote {
|
|
||||||
project_id,
|
|
||||||
client,
|
|
||||||
worktree_id,
|
|
||||||
work_directory_id,
|
|
||||||
} => {
|
|
||||||
client
|
|
||||||
.request(proto::Stage {
|
|
||||||
project_id: project_id.0,
|
|
||||||
worktree_id: worktree_id.to_proto(),
|
|
||||||
work_directory_id: work_directory_id.to_proto(),
|
|
||||||
paths: paths
|
|
||||||
.into_iter()
|
|
||||||
.map(|repo_path| repo_path.to_proto())
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.context("sending stage request")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Message::Unstage(repo, paths) => {
|
|
||||||
match repo {
|
|
||||||
GitRepo::Local(repo) => repo.unstage_paths(&paths)?,
|
|
||||||
GitRepo::Remote {
|
|
||||||
project_id,
|
|
||||||
client,
|
|
||||||
worktree_id,
|
|
||||||
work_directory_id,
|
|
||||||
} => {
|
|
||||||
client
|
|
||||||
.request(proto::Unstage {
|
|
||||||
project_id: project_id.0,
|
|
||||||
worktree_id: worktree_id.to_proto(),
|
|
||||||
work_directory_id: work_directory_id.to_proto(),
|
|
||||||
paths: paths
|
|
||||||
.into_iter()
|
|
||||||
.map(|repo_path| repo_path.to_proto())
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.context("sending unstage request")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Message::Commit {
|
|
||||||
git_repo,
|
|
||||||
name_and_email,
|
|
||||||
} => {
|
|
||||||
match git_repo {
|
|
||||||
GitRepo::Local(repo) => {
|
|
||||||
repo.commit(name_and_email.as_ref().map(
|
|
||||||
|(name, email)| (name.as_ref(), email.as_ref()),
|
|
||||||
))?
|
|
||||||
}
|
|
||||||
GitRepo::Remote {
|
|
||||||
project_id,
|
|
||||||
client,
|
|
||||||
worktree_id,
|
|
||||||
work_directory_id,
|
|
||||||
} => {
|
|
||||||
let (name, email) = name_and_email.unzip();
|
|
||||||
client
|
|
||||||
.request(proto::Commit {
|
|
||||||
project_id: project_id.0,
|
|
||||||
worktree_id: worktree_id.to_proto(),
|
|
||||||
work_directory_id: work_directory_id.to_proto(),
|
|
||||||
name: name.map(String::from),
|
|
||||||
email: email.map(String::from),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.context("sending commit request")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
if let Err(e) = result {
|
|
||||||
err_sender.send(e).await.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
|
|
||||||
let _subscription = cx.subscribe(worktree_store, Self::on_worktree_store_event);
|
let _subscription = cx.subscribe(worktree_store, Self::on_worktree_store_event);
|
||||||
|
|
||||||
GitState {
|
GitState {
|
||||||
|
@ -327,6 +178,110 @@ impl GitState {
|
||||||
pub fn all_repositories(&self) -> Vec<RepositoryHandle> {
|
pub fn all_repositories(&self) -> Vec<RepositoryHandle> {
|
||||||
self.repositories.clone()
|
self.repositories.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_git_worker(
|
||||||
|
cx: &mut Context<'_, GitState>,
|
||||||
|
) -> mpsc::UnboundedSender<(Message, oneshot::Sender<anyhow::Result<()>>)> {
|
||||||
|
let (update_sender, mut update_receiver) =
|
||||||
|
mpsc::unbounded::<(Message, oneshot::Sender<anyhow::Result<()>>)>();
|
||||||
|
cx.spawn(|_, cx| async move {
|
||||||
|
while let Some((msg, respond)) = update_receiver.next().await {
|
||||||
|
let result = cx
|
||||||
|
.background_executor()
|
||||||
|
.spawn(Self::process_git_msg(msg))
|
||||||
|
.await;
|
||||||
|
respond.send(result).ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
update_sender
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_git_msg(msg: Message) -> Result<(), anyhow::Error> {
|
||||||
|
match msg {
|
||||||
|
Message::Stage(repo, paths) => {
|
||||||
|
match repo {
|
||||||
|
GitRepo::Local(repo) => repo.stage_paths(&paths)?,
|
||||||
|
GitRepo::Remote {
|
||||||
|
project_id,
|
||||||
|
client,
|
||||||
|
worktree_id,
|
||||||
|
work_directory_id,
|
||||||
|
} => {
|
||||||
|
client
|
||||||
|
.request(proto::Stage {
|
||||||
|
project_id: project_id.0,
|
||||||
|
worktree_id: worktree_id.to_proto(),
|
||||||
|
work_directory_id: work_directory_id.to_proto(),
|
||||||
|
paths: paths
|
||||||
|
.into_iter()
|
||||||
|
.map(|repo_path| repo_path.to_proto())
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.context("sending stage request")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Message::Unstage(repo, paths) => {
|
||||||
|
match repo {
|
||||||
|
GitRepo::Local(repo) => repo.unstage_paths(&paths)?,
|
||||||
|
GitRepo::Remote {
|
||||||
|
project_id,
|
||||||
|
client,
|
||||||
|
worktree_id,
|
||||||
|
work_directory_id,
|
||||||
|
} => {
|
||||||
|
client
|
||||||
|
.request(proto::Unstage {
|
||||||
|
project_id: project_id.0,
|
||||||
|
worktree_id: worktree_id.to_proto(),
|
||||||
|
work_directory_id: work_directory_id.to_proto(),
|
||||||
|
paths: paths
|
||||||
|
.into_iter()
|
||||||
|
.map(|repo_path| repo_path.to_proto())
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.context("sending unstage request")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Message::Commit {
|
||||||
|
git_repo,
|
||||||
|
name_and_email,
|
||||||
|
} => {
|
||||||
|
match git_repo {
|
||||||
|
GitRepo::Local(repo) => repo.commit(
|
||||||
|
name_and_email
|
||||||
|
.as_ref()
|
||||||
|
.map(|(name, email)| (name.as_ref(), email.as_ref())),
|
||||||
|
)?,
|
||||||
|
GitRepo::Remote {
|
||||||
|
project_id,
|
||||||
|
client,
|
||||||
|
worktree_id,
|
||||||
|
work_directory_id,
|
||||||
|
} => {
|
||||||
|
let (name, email) = name_and_email.unzip();
|
||||||
|
client
|
||||||
|
.request(proto::Commit {
|
||||||
|
project_id: project_id.0,
|
||||||
|
worktree_id: worktree_id.to_proto(),
|
||||||
|
work_directory_id: work_directory_id.to_proto(),
|
||||||
|
name: name.map(String::from),
|
||||||
|
email: email.map(String::from),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.context("sending commit request")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepositoryHandle {
|
impl RepositoryHandle {
|
||||||
|
@ -379,54 +334,47 @@ impl RepositoryHandle {
|
||||||
self.repository_entry.relativize(&path.path).log_err()
|
self.repository_entry.relativize(&path.path).log_err()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stage_entries(
|
pub async fn stage_entries(&self, entries: Vec<RepoPath>) -> anyhow::Result<()> {
|
||||||
&self,
|
|
||||||
entries: Vec<RepoPath>,
|
|
||||||
err_sender: mpsc::Sender<anyhow::Error>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
if entries.is_empty() {
|
if entries.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let (result_tx, result_rx) = futures::channel::oneshot::channel();
|
||||||
self.update_sender
|
self.update_sender
|
||||||
.unbounded_send((Message::Stage(self.git_repo.clone(), entries), err_sender))
|
.unbounded_send((Message::Stage(self.git_repo.clone(), entries), result_tx))
|
||||||
.map_err(|_| anyhow!("Failed to submit stage operation"))?;
|
.map_err(|_| anyhow!("Failed to submit stage operation"))?;
|
||||||
Ok(())
|
|
||||||
|
result_rx.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unstage_entries(
|
pub async fn unstage_entries(&self, entries: Vec<RepoPath>) -> anyhow::Result<()> {
|
||||||
&self,
|
|
||||||
entries: Vec<RepoPath>,
|
|
||||||
err_sender: mpsc::Sender<anyhow::Error>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
if entries.is_empty() {
|
if entries.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let (result_tx, result_rx) = futures::channel::oneshot::channel();
|
||||||
self.update_sender
|
self.update_sender
|
||||||
.unbounded_send((Message::Unstage(self.git_repo.clone(), entries), err_sender))
|
.unbounded_send((Message::Unstage(self.git_repo.clone(), entries), result_tx))
|
||||||
.map_err(|_| anyhow!("Failed to submit unstage operation"))?;
|
.map_err(|_| anyhow!("Failed to submit unstage operation"))?;
|
||||||
Ok(())
|
result_rx.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stage_all(&self, err_sender: mpsc::Sender<anyhow::Error>) -> anyhow::Result<()> {
|
pub async fn stage_all(&self) -> anyhow::Result<()> {
|
||||||
let to_stage = self
|
let to_stage = self
|
||||||
.repository_entry
|
.repository_entry
|
||||||
.status()
|
.status()
|
||||||
.filter(|entry| !entry.status.is_staged().unwrap_or(false))
|
.filter(|entry| !entry.status.is_staged().unwrap_or(false))
|
||||||
.map(|entry| entry.repo_path.clone())
|
.map(|entry| entry.repo_path.clone())
|
||||||
.collect();
|
.collect();
|
||||||
self.stage_entries(to_stage, err_sender)?;
|
self.stage_entries(to_stage).await
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unstage_all(&self, err_sender: mpsc::Sender<anyhow::Error>) -> anyhow::Result<()> {
|
pub async fn unstage_all(&self) -> anyhow::Result<()> {
|
||||||
let to_unstage = self
|
let to_unstage = self
|
||||||
.repository_entry
|
.repository_entry
|
||||||
.status()
|
.status()
|
||||||
.filter(|entry| entry.status.is_staged().unwrap_or(true))
|
.filter(|entry| entry.status.is_staged().unwrap_or(true))
|
||||||
.map(|entry| entry.repo_path.clone())
|
.map(|entry| entry.repo_path.clone())
|
||||||
.collect();
|
.collect();
|
||||||
self.unstage_entries(to_unstage, err_sender)?;
|
self.unstage_entries(to_unstage).await
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a count of all entries in the active repository, including
|
/// Get a count of all entries in the active repository, including
|
||||||
|
@ -447,64 +395,18 @@ impl RepositoryHandle {
|
||||||
return self.have_changes() && (commit_all || self.have_staged_changes());
|
return self.have_changes() && (commit_all || self.have_staged_changes());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit(
|
pub async fn commit(
|
||||||
&self,
|
&self,
|
||||||
name_and_email: Option<(SharedString, SharedString)>,
|
name_and_email: Option<(SharedString, SharedString)>,
|
||||||
mut err_sender: mpsc::Sender<anyhow::Error>,
|
|
||||||
cx: &mut App,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let result = self.update_sender.unbounded_send((
|
let (result_tx, result_rx) = futures::channel::oneshot::channel();
|
||||||
|
self.update_sender.unbounded_send((
|
||||||
Message::Commit {
|
Message::Commit {
|
||||||
git_repo: self.git_repo.clone(),
|
git_repo: self.git_repo.clone(),
|
||||||
name_and_email,
|
name_and_email,
|
||||||
},
|
},
|
||||||
err_sender.clone(),
|
result_tx,
|
||||||
));
|
))?;
|
||||||
if result.is_err() {
|
result_rx.await?
|
||||||
cx.spawn(|_| async move {
|
|
||||||
err_sender
|
|
||||||
.send(anyhow!("Failed to submit commit operation"))
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
anyhow::bail!("Failed to submit commit operation");
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn commit_all(
|
|
||||||
&self,
|
|
||||||
name_and_email: Option<(SharedString, SharedString)>,
|
|
||||||
mut err_sender: mpsc::Sender<anyhow::Error>,
|
|
||||||
cx: &mut App,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let to_stage = self
|
|
||||||
.repository_entry
|
|
||||||
.status()
|
|
||||||
.filter(|entry| !entry.status.is_staged().unwrap_or(false))
|
|
||||||
.map(|entry| entry.repo_path.clone())
|
|
||||||
.collect();
|
|
||||||
let result = self.update_sender.unbounded_send((
|
|
||||||
Message::StageAndCommit {
|
|
||||||
git_repo: self.git_repo.clone(),
|
|
||||||
paths: to_stage,
|
|
||||||
name_and_email,
|
|
||||||
},
|
|
||||||
err_sender.clone(),
|
|
||||||
));
|
|
||||||
if result.is_err() {
|
|
||||||
cx.spawn(|_| async move {
|
|
||||||
err_sender
|
|
||||||
.send(anyhow!("Failed to submit commit all operation"))
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
anyhow::bail!("Failed to submit commit all operation");
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4006,15 +4006,9 @@ impl Project {
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(RepoPath::new)
|
.map(RepoPath::new)
|
||||||
.collect();
|
.collect();
|
||||||
let (err_sender, mut err_receiver) = mpsc::channel(1);
|
|
||||||
repository_handle
|
repository_handle.stage_entries(entries).await?;
|
||||||
.stage_entries(entries, err_sender)
|
Ok(proto::Ack {})
|
||||||
.context("staging entries")?;
|
|
||||||
if let Some(error) = err_receiver.next().await {
|
|
||||||
Err(error.context("error during staging"))
|
|
||||||
} else {
|
|
||||||
Ok(proto::Ack {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_unstage(
|
async fn handle_unstage(
|
||||||
|
@ -4034,15 +4028,9 @@ impl Project {
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(RepoPath::new)
|
.map(RepoPath::new)
|
||||||
.collect();
|
.collect();
|
||||||
let (err_sender, mut err_receiver) = mpsc::channel(1);
|
|
||||||
repository_handle
|
repository_handle.unstage_entries(entries).await?;
|
||||||
.unstage_entries(entries, err_sender)
|
Ok(proto::Ack {})
|
||||||
.context("unstaging entries")?;
|
|
||||||
if let Some(error) = err_receiver.next().await {
|
|
||||||
Err(error.context("error during unstaging"))
|
|
||||||
} else {
|
|
||||||
Ok(proto::Ack {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_commit(
|
async fn handle_commit(
|
||||||
|
@ -4057,17 +4045,8 @@ impl Project {
|
||||||
|
|
||||||
let name = envelope.payload.name.map(SharedString::from);
|
let name = envelope.payload.name.map(SharedString::from);
|
||||||
let email = envelope.payload.email.map(SharedString::from);
|
let email = envelope.payload.email.map(SharedString::from);
|
||||||
let (err_sender, mut err_receiver) = mpsc::channel(1);
|
repository_handle.commit(name.zip(email)).await?;
|
||||||
cx.update(|cx| {
|
Ok(proto::Ack {})
|
||||||
repository_handle
|
|
||||||
.commit(name.zip(email), err_sender, cx)
|
|
||||||
.context("unstaging entries")
|
|
||||||
})??;
|
|
||||||
if let Some(error) = err_receiver.next().await {
|
|
||||||
Err(error.context("error during unstaging"))
|
|
||||||
} else {
|
|
||||||
Ok(proto::Ack {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_open_commit_message_buffer(
|
async fn handle_open_commit_message_buffer(
|
||||||
|
|
|
@ -2,7 +2,6 @@ use anyhow::{anyhow, Context as _, Result};
|
||||||
use extension::ExtensionHostProxy;
|
use extension::ExtensionHostProxy;
|
||||||
use extension_host::headless_host::HeadlessExtensionStore;
|
use extension_host::headless_host::HeadlessExtensionStore;
|
||||||
use fs::{CreateOptions, Fs};
|
use fs::{CreateOptions, Fs};
|
||||||
use futures::channel::mpsc;
|
|
||||||
use git::{repository::RepoPath, COMMIT_MESSAGE};
|
use git::{repository::RepoPath, COMMIT_MESSAGE};
|
||||||
use gpui::{App, AppContext as _, AsyncApp, Context, Entity, PromptLevel, SharedString};
|
use gpui::{App, AppContext as _, AsyncApp, Context, Entity, PromptLevel, SharedString};
|
||||||
use http_client::HttpClient;
|
use http_client::HttpClient;
|
||||||
|
@ -637,15 +636,9 @@ impl HeadlessProject {
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(RepoPath::new)
|
.map(RepoPath::new)
|
||||||
.collect();
|
.collect();
|
||||||
let (err_sender, mut err_receiver) = mpsc::channel(1);
|
|
||||||
repository_handle
|
repository_handle.stage_entries(entries).await?;
|
||||||
.stage_entries(entries, err_sender)
|
Ok(proto::Ack {})
|
||||||
.context("staging entries")?;
|
|
||||||
if let Some(error) = err_receiver.next().await {
|
|
||||||
Err(error.context("error during staging"))
|
|
||||||
} else {
|
|
||||||
Ok(proto::Ack {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_unstage(
|
async fn handle_unstage(
|
||||||
|
@ -665,15 +658,10 @@ impl HeadlessProject {
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(RepoPath::new)
|
.map(RepoPath::new)
|
||||||
.collect();
|
.collect();
|
||||||
let (err_sender, mut err_receiver) = mpsc::channel(1);
|
|
||||||
repository_handle
|
repository_handle.unstage_entries(entries).await?;
|
||||||
.unstage_entries(entries, err_sender)
|
|
||||||
.context("unstaging entries")?;
|
Ok(proto::Ack {})
|
||||||
if let Some(error) = err_receiver.next().await {
|
|
||||||
Err(error.context("error during unstaging"))
|
|
||||||
} else {
|
|
||||||
Ok(proto::Ack {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_commit(
|
async fn handle_commit(
|
||||||
|
@ -688,17 +676,9 @@ impl HeadlessProject {
|
||||||
|
|
||||||
let name = envelope.payload.name.map(SharedString::from);
|
let name = envelope.payload.name.map(SharedString::from);
|
||||||
let email = envelope.payload.email.map(SharedString::from);
|
let email = envelope.payload.email.map(SharedString::from);
|
||||||
let (err_sender, mut err_receiver) = mpsc::channel(1);
|
|
||||||
cx.update(|cx| {
|
repository_handle.commit(name.zip(email)).await?;
|
||||||
repository_handle
|
Ok(proto::Ack {})
|
||||||
.commit(name.zip(email), err_sender, cx)
|
|
||||||
.context("unstaging entries")
|
|
||||||
})??;
|
|
||||||
if let Some(error) = err_receiver.next().await {
|
|
||||||
Err(error.context("error during unstaging"))
|
|
||||||
} else {
|
|
||||||
Ok(proto::Ack {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_open_commit_message_buffer(
|
async fn handle_open_commit_message_buffer(
|
||||||
|
|
|
@ -135,6 +135,11 @@ impl Checkbox {
|
||||||
ToggleStyle::Custom(color) => color.opacity(0.3),
|
ToggleStyle::Custom(color) => color.opacity(0.3),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// container size
|
||||||
|
pub fn container_size(cx: &App) -> Rems {
|
||||||
|
DynamicSpacing::Base20.rems(cx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderOnce for Checkbox {
|
impl RenderOnce for Checkbox {
|
||||||
|
@ -163,9 +168,13 @@ impl RenderOnce for Checkbox {
|
||||||
let bg_color = self.bg_color(cx);
|
let bg_color = self.bg_color(cx);
|
||||||
let border_color = self.border_color(cx);
|
let border_color = self.border_color(cx);
|
||||||
|
|
||||||
|
let size = Self::container_size(cx);
|
||||||
|
|
||||||
let checkbox = h_flex()
|
let checkbox = h_flex()
|
||||||
|
.id(self.id.clone())
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.size(DynamicSpacing::Base20.rems(cx))
|
.items_center()
|
||||||
|
.size(size)
|
||||||
.group(group_id.clone())
|
.group(group_id.clone())
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
|
|
|
@ -29,6 +29,23 @@ impl ToggleState {
|
||||||
Self::Selected => Self::Unselected,
|
Self::Selected => Self::Unselected,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a `ToggleState` from the given `any_checked` and `all_checked` flags.
|
||||||
|
pub fn from_any_and_all(any_checked: bool, all_checked: bool) -> Self {
|
||||||
|
match (any_checked, all_checked) {
|
||||||
|
(true, true) => Self::Selected,
|
||||||
|
(false, false) => Self::Unselected,
|
||||||
|
_ => Self::Indeterminate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this toggle state is selected
|
||||||
|
pub fn selected(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ToggleState::Indeterminate | ToggleState::Unselected => false,
|
||||||
|
ToggleState::Selected => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<bool> for ToggleState {
|
impl From<bool> for ToggleState {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue