mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +07:00
parent
2b6e935b09
commit
c9e6238163
4 changed files with 91 additions and 115 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -362,6 +362,7 @@ dependencies = [
|
|||
"fs",
|
||||
"futures 0.3.31",
|
||||
"fuzzy",
|
||||
"git_ui",
|
||||
"gpui",
|
||||
"gpui_tokio",
|
||||
"html_to_markdown",
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ feature_flags.workspace = true
|
|||
file_icons.workspace = true
|
||||
fs.workspace = true
|
||||
futures.workspace = true
|
||||
git_ui.workspace = true
|
||||
fuzzy.workspace = true
|
||||
gpui.workspace = true
|
||||
gpui_tokio.workspace = true
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use acp_thread::{
|
|||
ToolCallStatus, UserMessageId,
|
||||
};
|
||||
use acp_thread::{AgentConnection, Plan};
|
||||
use action_log::{ActionLog, ActionLogTelemetry};
|
||||
use action_log::ActionLogTelemetry;
|
||||
use agent::{DbThreadMetadata, NativeAgentServer, SharedThread, ThreadStore};
|
||||
use agent_client_protocol::{self as acp, PromptCapabilities};
|
||||
use agent_servers::{AgentServer, AgentServerDelegate};
|
||||
|
|
@ -45,7 +45,7 @@ use std::sync::Arc;
|
|||
use std::time::Instant;
|
||||
use std::{collections::BTreeMap, rc::Rc, time::Duration};
|
||||
use terminal_view::terminal_panel::TerminalPanel;
|
||||
use text::{Anchor, ToPoint as _};
|
||||
use text::ToPoint as _;
|
||||
use theme::{AgentFontSize, ThemeSettings};
|
||||
use ui::{
|
||||
Callout, CommonAnimationExt, ContextMenu, ContextMenuEntry, CopyButton, DiffStat, Disclosure,
|
||||
|
|
@ -71,8 +71,8 @@ use crate::ui::{AgentNotification, AgentNotificationEvent, BurnModeTooltip, Usag
|
|||
use crate::{
|
||||
AgentDiffPane, AgentPanel, AllowAlways, AllowOnce, ClearMessageQueue, ContinueThread,
|
||||
ContinueWithBurnMode, CycleFavoriteModels, CycleModeSelector, ExpandMessageEditor, Follow,
|
||||
KeepAll, NewThread, OpenAgentDiff, OpenHistory, QueueMessage, RejectAll, RejectOnce,
|
||||
SendNextQueuedMessage, ToggleBurnMode, ToggleProfileSelector,
|
||||
KeepAll, NewThread, OpenHistory, QueueMessage, RejectAll, RejectOnce, SendNextQueuedMessage,
|
||||
ToggleBurnMode, ToggleProfileSelector,
|
||||
};
|
||||
|
||||
const STOPWATCH_THRESHOLD: Duration = Duration::from_secs(1);
|
||||
|
|
@ -4341,7 +4341,6 @@ impl AcpThreadView {
|
|||
) -> Option<AnyElement> {
|
||||
let thread = thread_entity.read(cx);
|
||||
let action_log = thread.action_log();
|
||||
let telemetry = ActionLogTelemetry::from(thread);
|
||||
let changed_buffers = action_log.read(cx).changed_buffers(cx);
|
||||
let plan = thread.plan();
|
||||
|
||||
|
|
@ -4387,13 +4386,7 @@ impl AcpThreadView {
|
|||
cx,
|
||||
))
|
||||
.when(self.edits_expanded, |parent| {
|
||||
parent.child(self.render_edited_files(
|
||||
action_log,
|
||||
telemetry,
|
||||
&changed_buffers,
|
||||
pending_edits,
|
||||
cx,
|
||||
))
|
||||
parent.child(self.render_edited_files(&changed_buffers, cx))
|
||||
})
|
||||
})
|
||||
.when(!self.message_queue.is_empty(), |this| {
|
||||
|
|
@ -4571,8 +4564,6 @@ impl AcpThreadView {
|
|||
pending_edits: bool,
|
||||
cx: &Context<Self>,
|
||||
) -> Div {
|
||||
const EDIT_NOT_READY_TOOLTIP_LABEL: &str = "Wait until file edits are complete.";
|
||||
|
||||
let focus_handle = self.focus_handle(cx);
|
||||
|
||||
h_flex()
|
||||
|
|
@ -4651,66 +4642,21 @@ impl AcpThreadView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
IconButton::new("review-changes", IconName::ListTodo)
|
||||
.icon_size(IconSize::Small)
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |_window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Review Changes",
|
||||
&OpenAgentDiff,
|
||||
&focus_handle,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
})
|
||||
.on_click(cx.listener(|_, _, window, cx| {
|
||||
window.dispatch_action(OpenAgentDiff.boxed_clone(), cx);
|
||||
})),
|
||||
Button::new("review-changes", "Review Changes")
|
||||
.label_size(LabelSize::Small)
|
||||
.key_binding(
|
||||
KeyBinding::for_action_in(&git_ui::project_diff::Diff, &focus_handle, cx)
|
||||
.map(|kb| kb.size(rems_from_px(10.))),
|
||||
)
|
||||
.child(Divider::vertical().color(DividerColor::Border))
|
||||
.child(
|
||||
Button::new("reject-all-changes", "Reject All")
|
||||
.label_size(LabelSize::Small)
|
||||
.disabled(pending_edits)
|
||||
.when(pending_edits, |this| {
|
||||
this.tooltip(Tooltip::text(EDIT_NOT_READY_TOOLTIP_LABEL))
|
||||
})
|
||||
.key_binding(
|
||||
KeyBinding::for_action_in(&RejectAll, &focus_handle.clone(), cx)
|
||||
.map(|kb| kb.size(rems_from_px(10.))),
|
||||
)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.reject_all(&RejectAll, window, cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("keep-all-changes", "Keep All")
|
||||
.label_size(LabelSize::Small)
|
||||
.disabled(pending_edits)
|
||||
.when(pending_edits, |this| {
|
||||
this.tooltip(Tooltip::text(EDIT_NOT_READY_TOOLTIP_LABEL))
|
||||
})
|
||||
.key_binding(
|
||||
KeyBinding::for_action_in(&KeepAll, &focus_handle, cx)
|
||||
.map(|kb| kb.size(rems_from_px(10.))),
|
||||
)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.keep_all(&KeepAll, window, cx);
|
||||
})),
|
||||
),
|
||||
.on_click(cx.listener(move |_, _, window, cx| {
|
||||
window.dispatch_action(git_ui::project_diff::Diff.boxed_clone(), cx);
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_edited_files(
|
||||
&self,
|
||||
action_log: &Entity<ActionLog>,
|
||||
telemetry: ActionLogTelemetry,
|
||||
changed_buffers: &BTreeMap<Entity<Buffer>, Entity<BufferDiff>>,
|
||||
pending_edits: bool,
|
||||
cx: &Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let editor_bg_color = cx.theme().colors().editor_background;
|
||||
|
|
@ -4843,56 +4789,27 @@ impl AcpThreadView {
|
|||
.label_size(LabelSize::Small)
|
||||
.on_click({
|
||||
let buffer = buffer.clone();
|
||||
cx.listener(move |this, _, window, cx| {
|
||||
this.open_edited_buffer(&buffer, window, cx);
|
||||
})
|
||||
}),
|
||||
)
|
||||
.child(Divider::vertical().color(DividerColor::BorderVariant))
|
||||
.child(
|
||||
Button::new("reject-file", "Reject")
|
||||
.label_size(LabelSize::Small)
|
||||
.disabled(pending_edits)
|
||||
.on_click({
|
||||
let buffer = buffer.clone();
|
||||
let action_log = action_log.clone();
|
||||
let telemetry = telemetry.clone();
|
||||
move |_, _, cx| {
|
||||
action_log.update(cx, |action_log, cx| {
|
||||
action_log
|
||||
.reject_edits_in_ranges(
|
||||
buffer.clone(),
|
||||
vec![Anchor::min_max_range_for_buffer(
|
||||
buffer.read(cx).remote_id(),
|
||||
)],
|
||||
Some(telemetry.clone()),
|
||||
cx,
|
||||
)
|
||||
.detach_and_log_err(cx);
|
||||
})
|
||||
}
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("keep-file", "Keep")
|
||||
.label_size(LabelSize::Small)
|
||||
.disabled(pending_edits)
|
||||
.on_click({
|
||||
let buffer = buffer.clone();
|
||||
let action_log = action_log.clone();
|
||||
let telemetry = telemetry.clone();
|
||||
move |_, _, cx| {
|
||||
action_log.update(cx, |action_log, cx| {
|
||||
action_log.keep_edits_in_range(
|
||||
buffer.clone(),
|
||||
Anchor::min_max_range_for_buffer(
|
||||
buffer.read(cx).remote_id(),
|
||||
),
|
||||
Some(telemetry.clone()),
|
||||
let workspace = self.workspace.clone();
|
||||
cx.listener(move |_, _, window, cx| {
|
||||
let Some(workspace) = workspace.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(file) = buffer.read(cx).file() else {
|
||||
return;
|
||||
};
|
||||
let project_path = project::ProjectPath {
|
||||
worktree_id: file.worktree_id(cx),
|
||||
path: file.path().clone(),
|
||||
};
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
git_ui::project_diff::ProjectDiff::deploy_at_project_path(
|
||||
workspace,
|
||||
project_path,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
|
@ -7291,6 +7208,7 @@ fn terminal_command_markdown_style(window: &Window, cx: &App) -> MarkdownStyle {
|
|||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use acp_thread::StubAgentConnection;
|
||||
use action_log::ActionLog;
|
||||
use agent_client_protocol::SessionId;
|
||||
use editor::MultiBufferOffset;
|
||||
use fs::FakeFs;
|
||||
|
|
|
|||
|
|
@ -182,6 +182,37 @@ impl ProjectDiff {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn deploy_at_project_path(
|
||||
workspace: &mut Workspace,
|
||||
project_path: ProjectPath,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Workspace>,
|
||||
) {
|
||||
telemetry::event!("Git Diff Opened", source = "Agent Panel");
|
||||
let existing = workspace
|
||||
.items_of_type::<Self>(cx)
|
||||
.find(|item| matches!(item.read(cx).diff_base(cx), DiffBase::Head));
|
||||
let project_diff = if let Some(existing) = existing {
|
||||
workspace.activate_item(&existing, true, true, window, cx);
|
||||
existing
|
||||
} else {
|
||||
let workspace_handle = cx.entity();
|
||||
let project_diff =
|
||||
cx.new(|cx| Self::new(workspace.project().clone(), workspace_handle, window, cx));
|
||||
workspace.add_item_to_active_pane(
|
||||
Box::new(project_diff.clone()),
|
||||
None,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
project_diff
|
||||
};
|
||||
project_diff.update(cx, |project_diff, cx| {
|
||||
project_diff.move_to_project_path(&project_path, window, cx);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn autoscroll(&self, cx: &mut Context<Self>) {
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
editor.primary_editor().update(cx, |editor, cx| {
|
||||
|
|
@ -356,6 +387,31 @@ impl ProjectDiff {
|
|||
self.move_to_path(path_key, window, cx)
|
||||
}
|
||||
|
||||
pub fn move_to_project_path(
|
||||
&mut self,
|
||||
project_path: &ProjectPath,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(git_repo) = self.branch_diff.read(cx).repo() else {
|
||||
return;
|
||||
};
|
||||
let Some(repo_path) = git_repo
|
||||
.read(cx)
|
||||
.project_path_to_repo_path(project_path, cx)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let status = git_repo
|
||||
.read(cx)
|
||||
.status_for_path(&repo_path)
|
||||
.map(|entry| entry.status)
|
||||
.unwrap_or(FileStatus::Untracked);
|
||||
let sort_prefix = sort_prefix(&git_repo.read(cx), &repo_path, status, cx);
|
||||
let path_key = PathKey::with_sort_prefix(sort_prefix, repo_path.as_ref().clone());
|
||||
self.move_to_path(path_key, window, cx)
|
||||
}
|
||||
|
||||
pub fn active_path(&self, cx: &App) -> Option<ProjectPath> {
|
||||
let editor = self.editor.read(cx).last_selected_editor().read(cx);
|
||||
let position = editor.selections.newest_anchor().head();
|
||||
|
|
|
|||
Loading…
Reference in a new issue