Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 5 additions & 173 deletions crates/agent_ui/src/inline_assistant.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use language_models::provider::anthropic::telemetry::{
AnthropicCompletionType, AnthropicEventData, AnthropicEventType, report_anthropic_event,
};
use std::cmp;
use std::mem;
use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
use uuid::Uuid;

Expand All @@ -27,8 +25,8 @@ use editor::RowExt;
use editor::SelectionEffects;
use editor::scroll::ScrollOffset;
use editor::{
Anchor, AnchorRangeExt, CodeActionProvider, Editor, EditorEvent, HighlightKey, MultiBuffer,
MultiBufferSnapshot, ToOffset as _, ToPoint,
Anchor, AnchorRangeExt, Editor, EditorEvent, HighlightKey, MultiBuffer, MultiBufferSnapshot,
ToOffset as _, ToPoint,
actions::SelectAll,
display_map::{
BlockContext, BlockPlacement, BlockProperties, BlockStyle, CustomBlockId, EditorMargins,
Expand All @@ -45,15 +43,14 @@ use language::{Buffer, Point, Selection, TransactionId};
use language_model::{ConfigurationError, ConfiguredModel, LanguageModelRegistry};
use multi_buffer::MultiBufferRow;
use parking_lot::Mutex;
use project::{CodeAction, DisableAiSettings, LspAction, Project, ProjectTransaction};
use project::{DisableAiSettings, Project};
use prompt_store::{PromptBuilder, PromptStore};
use settings::{Settings, SettingsStore};

use terminal_view::{TerminalView, terminal_panel::TerminalPanel};
use text::{OffsetRangeExt, ToPoint as _};
use ui::prelude::*;
use util::{RangeExt, ResultExt, maybe};
use workspace::{ItemHandle, Toast, Workspace, dock::Panel, notifications::NotificationId};
use workspace::{Toast, Workspace, dock::Panel, notifications::NotificationId};
use zed_actions::agent::OpenSettings;

pub fn init(fs: Arc<dyn Fs>, prompt_builder: Arc<PromptBuilder>, cx: &mut App) {
Expand Down Expand Up @@ -184,7 +181,7 @@ impl InlineAssistant {

fn handle_workspace_event(
&mut self,
workspace: Entity<Workspace>,
_workspace: Entity<Workspace>,
event: &workspace::Event,
window: &mut Window,
cx: &mut App,
Expand All @@ -203,51 +200,10 @@ impl InlineAssistant {
}
}
}
workspace::Event::ItemAdded { item } => {
self.register_workspace_item(&workspace, item.as_ref(), window, cx);
}
_ => (),
}
}

fn register_workspace_item(
&mut self,
workspace: &Entity<Workspace>,
item: &dyn ItemHandle,
window: &mut Window,
cx: &mut App,
) {
let is_ai_enabled = !DisableAiSettings::get_global(cx).disable_ai;

if let Some(editor) = item.act_as::<Editor>(cx) {
editor.update(cx, |editor, cx| {
if is_ai_enabled {
editor.add_code_action_provider(
Rc::new(AssistantCodeActionProvider {
editor: cx.entity().downgrade(),
workspace: workspace.downgrade(),
}),
window,
cx,
);

if DisableAiSettings::get_global(cx).disable_ai {
// Cancel any active edit predictions
if editor.has_active_edit_prediction() {
editor.cancel(&Default::default(), window, cx);
}
}
} else {
editor.remove_code_action_provider(
ASSISTANT_CODE_ACTION_PROVIDER_ID.into(),
window,
cx,
);
}
});
}
}

pub fn inline_assist(
workspace: &mut Workspace,
action: &zed_actions::assistant::InlineAssist,
Expand Down Expand Up @@ -1875,130 +1831,6 @@ struct InlineAssistDecorations {
end_block_id: CustomBlockId,
}

struct AssistantCodeActionProvider {
editor: WeakEntity<Editor>,
workspace: WeakEntity<Workspace>,
}

const ASSISTANT_CODE_ACTION_PROVIDER_ID: &str = "assistant";

impl CodeActionProvider for AssistantCodeActionProvider {
fn id(&self) -> Arc<str> {
ASSISTANT_CODE_ACTION_PROVIDER_ID.into()
}

fn code_actions(
&self,
buffer: &Entity<Buffer>,
range: Range<text::Anchor>,
_: &mut Window,
cx: &mut App,
) -> Task<Result<Vec<CodeAction>>> {
if !AgentSettings::get_global(cx).enabled(cx) {
return Task::ready(Ok(Vec::new()));
}

let snapshot = buffer.read(cx).snapshot();
let mut range = range.to_point(&snapshot);

// Expand the range to line boundaries.
range.start.column = 0;
range.end.column = snapshot.line_len(range.end.row);

let mut has_diagnostics = false;
for diagnostic in snapshot.diagnostics_in_range::<_, Point>(range.clone(), false) {
range.start = cmp::min(range.start, diagnostic.range.start);
range.end = cmp::max(range.end, diagnostic.range.end);
has_diagnostics = true;
}
if has_diagnostics {
let symbols_containing_start = snapshot.symbols_containing(range.start, None);
if let Some(symbol) = symbols_containing_start.last() {
range.start = cmp::min(range.start, symbol.range.start.to_point(&snapshot));
range.end = cmp::max(range.end, symbol.range.end.to_point(&snapshot));
}
let symbols_containing_end = snapshot.symbols_containing(range.end, None);
if let Some(symbol) = symbols_containing_end.last() {
range.start = cmp::min(range.start, symbol.range.start.to_point(&snapshot));
range.end = cmp::max(range.end, symbol.range.end.to_point(&snapshot));
}

Task::ready(Ok(vec![CodeAction {
server_id: language::LanguageServerId(0),
range: snapshot.anchor_before(range.start)..snapshot.anchor_after(range.end),
lsp_action: LspAction::Action(Box::new(lsp::CodeAction {
title: "Fix with Assistant".into(),
..Default::default()
})),
resolved: true,
}]))
} else {
Task::ready(Ok(Vec::new()))
}
}

fn apply_code_action(
&self,
_buffer: Entity<Buffer>,
action: CodeAction,
_push_to_history: bool,
window: &mut Window,
cx: &mut App,
) -> Task<Result<ProjectTransaction>> {
let editor = self.editor.clone();
let workspace = self.workspace.clone();
let prompt_store = PromptStore::global(cx);
window.spawn(cx, async move |cx| {
let workspace = workspace.upgrade().context("workspace was released")?;
let (thread_store, history) = cx.update(|_window, cx| {
let panel = workspace
.read(cx)
.panel::<AgentPanel>(cx)
.context("missing agent panel")?
.read(cx);

let history = panel
.connection_store()
.read(cx)
.entry(&crate::Agent::NativeAgent)
.and_then(|e| e.read(cx).history())
.map(|h| h.downgrade());

anyhow::Ok((panel.thread_store().clone(), history))
})??;
let editor = editor.upgrade().context("editor was released")?;
let range = editor
.update(cx, |editor, cx| {
editor.buffer().update(cx, |multibuffer, cx| {
let multibuffer_snapshot = multibuffer.read(cx);
multibuffer_snapshot.buffer_anchor_range_to_anchor_range(action.range)
})
})
.context("invalid range")?;

let prompt_store = prompt_store.await.ok();
cx.update_global(|assistant: &mut InlineAssistant, window, cx| {
let assist_id = assistant.suggest_assist(
&editor,
range,
"Fix Diagnostics".into(),
None,
true,
workspace,
thread_store,
prompt_store,
history,
window,
cx,
);
assistant.start_assist(assist_id, window, cx);
})?;

Ok(ProjectTransaction::default())
})
}
}

fn merge_ranges(ranges: &mut Vec<Range<Anchor>>, buffer: &MultiBufferSnapshot) {
ranges.sort_unstable_by(|a, b| {
a.start
Expand Down
Loading