diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index a85cb86de4b71c8fc70783b643b13087eeb4d22f..0ed0aeb78bf8889136a479ed2dac5caba633db55 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -66,7 +66,10 @@ use project::project_settings::ProjectSettings; use project::{Project, ProjectPath, Worktree}; use prompt_store::{PromptStore, UserPromptId}; use rules_library::{RulesLibrary, open_rules_library}; +use settings::TerminalDockPosition; use settings::{Settings, update_settings_file}; +use terminal::terminal_settings::TerminalSettings; +use terminal_view::{TerminalView, terminal_panel::TerminalPanel}; use theme_settings::ThemeSettings; use ui::{ Button, Callout, CommonAnimationExt, ContextMenu, ContextMenuEntry, DocumentationSide, @@ -423,6 +426,48 @@ pub fn init(cx: &mut App) { }) .register_action( |workspace: &mut Workspace, _: &AddSelectionToThread, window, cx| { + let active_editor = workspace + .active_item(cx) + .and_then(|item| item.act_as::(cx)); + let has_editor_selection = active_editor.is_some_and(|editor| { + editor.update(cx, |editor, cx| { + editor.has_non_empty_selection(&editor.display_snapshot(cx)) + }) + }); + + let has_terminal_selection = workspace + .active_item(cx) + .and_then(|item| item.act_as::(cx)) + .is_some_and(|terminal_view| { + terminal_view + .read(cx) + .terminal() + .read(cx) + .last_content + .selection_text + .as_ref() + .is_some_and(|text| !text.is_empty()) + }); + + let has_terminal_panel_selection = + workspace.panel::(cx).is_some_and(|panel| { + let position = match TerminalSettings::get_global(cx).dock { + TerminalDockPosition::Left => DockPosition::Left, + TerminalDockPosition::Bottom => DockPosition::Bottom, + TerminalDockPosition::Right => DockPosition::Right, + }; + let dock_is_open = + workspace.dock_at_position(position).read(cx).is_open(); + dock_is_open && !panel.read(cx).terminal_selections(cx).is_empty() + }); + + if !has_editor_selection + && !has_terminal_selection + && !has_terminal_panel_selection + { + return; + } + let Some(panel) = workspace.panel::(cx) else { return; }; diff --git a/crates/agent_ui/src/completion_provider.rs b/crates/agent_ui/src/completion_provider.rs index b6be6502b152847822a79bc8c486195345c0a195..6259269834b0add5b87fd9d397e17671d30adb9f 100644 --- a/crates/agent_ui/src/completion_provider.rs +++ b/crates/agent_ui/src/completion_provider.rs @@ -28,7 +28,7 @@ use prompt_store::{PromptStore, UserPromptId}; use rope::Point; use settings::{Settings, TerminalDockPosition}; use terminal::terminal_settings::TerminalSettings; -use terminal_view::terminal_panel::TerminalPanel; +use terminal_view::{TerminalView, terminal_panel::TerminalPanel}; use text::{Anchor, ToOffset as _, ToPoint as _}; use ui::IconName; use ui::prelude::*; @@ -562,8 +562,7 @@ impl PromptCompletionProvider { .collect(); // Collect terminal selections from all terminal views if the terminal panel is visible - let terminal_selections: Vec = - terminal_selections_if_panel_open(workspace, cx); + let terminal_selections: Vec = terminal_selections(workspace, cx); const EDITOR_PLACEHOLDER: &str = "selection "; const TERMINAL_PLACEHOLDER: &str = "terminal "; @@ -1198,7 +1197,7 @@ impl PromptCompletionProvider { }) }); - let has_terminal_selection = !terminal_selections_if_panel_open(workspace, cx).is_empty(); + let has_terminal_selection = !terminal_selections(workspace, cx).is_empty(); if has_editor_selection || has_terminal_selection { entries.push(PromptContextEntry::Action( @@ -2169,28 +2168,45 @@ fn build_code_label_for_path( label.build() } -/// Returns terminal selections from all terminal views if the terminal panel is open. -fn terminal_selections_if_panel_open(workspace: &Entity, cx: &App) -> Vec { - let Some(panel) = workspace.read(cx).panel::(cx) else { - return Vec::new(); - }; +fn terminal_selections(workspace: &Entity, cx: &App) -> Vec { + let mut selections = Vec::new(); - // Check if the dock containing this panel is open - let position = match TerminalSettings::get_global(cx).dock { - TerminalDockPosition::Left => DockPosition::Left, - TerminalDockPosition::Bottom => DockPosition::Bottom, - TerminalDockPosition::Right => DockPosition::Right, - }; - let dock_is_open = workspace + // Check if the active item is a terminal (in a panel or not) + if let Some(terminal_view) = workspace .read(cx) - .dock_at_position(position) - .read(cx) - .is_open(); - if !dock_is_open { - return Vec::new(); + .active_item(cx) + .and_then(|item| item.act_as::(cx)) + { + if let Some(text) = terminal_view + .read(cx) + .terminal() + .read(cx) + .last_content + .selection_text + .clone() + .filter(|text| !text.is_empty()) + { + selections.push(text); + } } - panel.read(cx).terminal_selections(cx) + if let Some(panel) = workspace.read(cx).panel::(cx) { + let position = match TerminalSettings::get_global(cx).dock { + TerminalDockPosition::Left => DockPosition::Left, + TerminalDockPosition::Bottom => DockPosition::Bottom, + TerminalDockPosition::Right => DockPosition::Right, + }; + let dock_is_open = workspace + .read(cx) + .dock_at_position(position) + .read(cx) + .is_open(); + if dock_is_open { + selections.extend(panel.read(cx).terminal_selections(cx)); + } + } + + selections } fn selection_ranges( @@ -2213,17 +2229,8 @@ fn selection_ranges( selections .into_iter() - .map(|s| { - let (start, end) = if s.is_empty() { - let row = multi_buffer::MultiBufferRow(s.start.row); - let line_start = text::Point::new(s.start.row, 0); - let line_end = text::Point::new(s.start.row, snapshot.line_len(row)); - (line_start, line_end) - } else { - (s.start, s.end) - }; - snapshot.anchor_after(start)..snapshot.anchor_before(end) - }) + .filter(|s| !s.is_empty()) + .map(|s| snapshot.anchor_after(s.start)..snapshot.anchor_before(s.end)) .flat_map(|range| { let (start_buffer, start) = buffer.text_anchor_for_position(range.start, cx)?; let (end_buffer, end) = buffer.text_anchor_for_position(range.end, cx)?;