Detailed changes
@@ -54,7 +54,9 @@ pub enum MentionUri {
Fetch {
url: Url,
},
- TerminalSelection,
+ TerminalSelection {
+ line_count: u32,
+ },
}
impl MentionUri {
@@ -201,7 +203,11 @@ impl MentionUri {
line_range,
})
} else if path.starts_with("/agent/terminal-selection") {
- Ok(Self::TerminalSelection)
+ let line_count = single_query_param(&url, "lines")?
+ .unwrap_or_else(|| "0".to_string())
+ .parse::<u32>()
+ .unwrap_or(0);
+ Ok(Self::TerminalSelection { line_count })
} else {
bail!("invalid zed url: {:?}", input);
}
@@ -224,7 +230,13 @@ impl MentionUri {
MentionUri::TextThread { name, .. } => name.clone(),
MentionUri::Rule { name, .. } => name.clone(),
MentionUri::Diagnostics { .. } => "Diagnostics".to_string(),
- MentionUri::TerminalSelection => "Terminal".to_string(),
+ MentionUri::TerminalSelection { line_count } => {
+ if *line_count == 1 {
+ "Terminal (1 line)".to_string()
+ } else {
+ format!("Terminal ({} lines)", line_count)
+ }
+ }
MentionUri::Selection {
abs_path: path,
line_range,
@@ -247,7 +259,7 @@ impl MentionUri {
MentionUri::TextThread { .. } => IconName::Thread.path().into(),
MentionUri::Rule { .. } => IconName::Reader.path().into(),
MentionUri::Diagnostics { .. } => IconName::Warning.path().into(),
- MentionUri::TerminalSelection => IconName::Terminal.path().into(),
+ MentionUri::TerminalSelection { .. } => IconName::Terminal.path().into(),
MentionUri::Selection { .. } => IconName::Reader.path().into(),
MentionUri::Fetch { .. } => IconName::ToolWeb.path().into(),
}
@@ -342,7 +354,12 @@ impl MentionUri {
url
}
MentionUri::Fetch { url } => url.clone(),
- MentionUri::TerminalSelection => Url::parse("zed:///agent/terminal-selection").unwrap(),
+ MentionUri::TerminalSelection { line_count } => {
+ let mut url = Url::parse("zed:///agent/terminal-selection").unwrap();
+ url.query_pairs_mut()
+ .append_pair("lines", &line_count.to_string());
+ url
+ }
}
}
}
@@ -650,13 +667,20 @@ mod tests {
#[test]
fn test_parse_terminal_selection_uri() {
- let terminal_uri = "zed:///agent/terminal-selection";
+ let terminal_uri = "zed:///agent/terminal-selection?lines=42";
let parsed = MentionUri::parse(terminal_uri, PathStyle::local()).unwrap();
match &parsed {
- MentionUri::TerminalSelection => {}
- _ => panic!("Expected Terminal variant"),
+ MentionUri::TerminalSelection { line_count } => {
+ assert_eq!(*line_count, 42);
+ }
+ _ => panic!("Expected TerminalSelection variant"),
}
assert_eq!(parsed.to_uri().to_string(), terminal_uri);
- assert_eq!(parsed.name(), "Terminal");
+ assert_eq!(parsed.name(), "Terminal (42 lines)");
+
+ // Test single line
+ let single_line_uri = "zed:///agent/terminal-selection?lines=1";
+ let parsed_single = MentionUri::parse(single_line_uri, PathStyle::local()).unwrap();
+ assert_eq!(parsed_single.name(), "Terminal (1 line)");
}
}
@@ -317,7 +317,7 @@ impl UserMessage {
MentionUri::Diagnostics { .. } => {
write!(&mut diagnostics_context, "\n{}\n", content).ok();
}
- MentionUri::TerminalSelection => {
+ MentionUri::TerminalSelection { .. } => {
write!(
&mut selection_context,
"\n{}",
@@ -1017,7 +1017,8 @@ impl MessageEditor {
window: &mut Window,
cx: &mut Context<Self>,
) {
- let mention_uri = MentionUri::TerminalSelection;
+ let line_count = text.lines().count() as u32;
+ let mention_uri = MentionUri::TerminalSelection { line_count };
let mention_text = mention_uri.as_link().to_string();
let (excerpt_id, text_anchor, content_len) = self.editor.update(cx, |editor, cx| {
@@ -6621,7 +6621,7 @@ impl AcpThreadView {
.map(|active| active.prompt_capabilities.borrow().image)
.unwrap_or_default();
- let has_selection = workspace
+ let has_editor_selection = workspace
.upgrade()
.and_then(|ws| {
ws.read(cx)
@@ -6634,6 +6634,13 @@ impl AcpThreadView {
})
});
+ let has_terminal_selection = workspace
+ .upgrade()
+ .and_then(|ws| ws.read(cx).panel::<TerminalPanel>(cx))
+ .is_some_and(|panel| !panel.read(cx).terminal_selections(cx).is_empty());
+
+ let has_selection = has_editor_selection || has_terminal_selection;
+
ContextMenu::build(window, cx, move |menu, _window, _cx| {
menu.key_context("AddContextMenu")
.header("Context")
@@ -6721,10 +6728,10 @@ impl AcpThreadView {
.disabled(!has_selection)
.handler({
move |window, cx| {
- message_editor.focus_handle(cx).focus(window, cx);
- message_editor.update(cx, |editor, cx| {
- editor.insert_selections(window, cx);
- });
+ window.dispatch_action(
+ zed_actions::agent::AddSelectionToThread.boxed_clone(),
+ cx,
+ );
}
}),
)
@@ -6870,7 +6877,7 @@ impl AcpThreadView {
cx.open_url(url.as_str());
}
MentionUri::Diagnostics { .. } => {}
- MentionUri::TerminalSelection => {}
+ MentionUri::TerminalSelection { .. } => {}
})
} else {
cx.open_url(&url);
@@ -636,7 +636,8 @@ impl<T: PromptCompletionProviderDelegate> PromptCompletionProvider<T> {
};
let offset = start.to_offset(&snapshot);
- let mention_uri = MentionUri::TerminalSelection;
+ let line_count = terminal_text.lines().count() as u32;
+ let mention_uri = MentionUri::TerminalSelection { line_count };
let range = snapshot.anchor_after(offset + terminal_range.start)
..snapshot.anchor_after(offset + terminal_range.end);
@@ -249,7 +249,7 @@ impl MentionSet {
debug_panic!("unexpected selection URI");
Task::ready(Err(anyhow!("unexpected selection URI")))
}
- MentionUri::TerminalSelection => {
+ MentionUri::TerminalSelection { .. } => {
debug_panic!("unexpected terminal URI");
Task::ready(Err(anyhow!("unexpected terminal URI")))
}
@@ -65,10 +65,8 @@ use workspace::{
searchable::{Direction, SearchableItemHandle},
};
-use terminal_view::{TerminalView, terminal_panel::TerminalPanel};
use workspace::{
Save, Toast, Workspace,
- dock::Panel,
item::{self, FollowableItem, Item},
notifications::NotificationId,
pane,
@@ -1498,39 +1496,8 @@ impl TextThreadEditor {
return;
};
- // Try terminal selection first (requires focus, so more specific)
- if let Some(terminal_text) = maybe!({
- let terminal_panel = workspace.panel::<TerminalPanel>(cx)?;
-
- if !terminal_panel
- .read(cx)
- .focus_handle(cx)
- .contains_focused(window, cx)
- {
- return None;
- }
-
- let terminal_view = terminal_panel.read(cx).pane().and_then(|pane| {
- pane.read(cx)
- .active_item()
- .and_then(|t| t.downcast::<TerminalView>())
- })?;
-
- terminal_view
- .read(cx)
- .terminal()
- .read(cx)
- .last_content
- .selection_text
- .clone()
- }) {
- if !terminal_text.is_empty() {
- agent_panel_delegate.quote_terminal_text(workspace, terminal_text, window, cx);
- return;
- }
- }
-
- // Try editor selection
+ // Get buffer info for the delegate call (even if empty, AcpThreadView ignores these
+ // params and calls insert_selections which handles both terminal and buffer)
if let Some((selections, buffer)) = maybe!({
let editor = workspace
.active_item(cx)
@@ -1551,9 +1518,7 @@ impl TextThreadEditor {
});
Some((selections, buffer))
}) {
- if !selections.is_empty() {
- agent_panel_delegate.quote_selection(workspace, selections, buffer, window, cx);
- }
+ agent_panel_delegate.quote_selection(workspace, selections, buffer, window, cx);
}
}