agent: Make agent::addSelectionToThread use current line when no selection (#48045)

Peter Tripp and Bennet Bo Fenner created

When there is no selection, make `cmd->` (`agent::addSelectionToThread`)
use the current line containing the cursor instead of doing nothing.

Supports both Zed Agent and Zed Assistant.
Works with multiple-cursors and a mix of selections and cursors.

Authored by Claude Opus 4.5, tested by me.

Release Notes:

- agent: Make `agent::addSelectionToThread` (`cmd->`) use the current
line of the cursor when there is no selection.

---------

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>

Change summary

crates/agent_ui/src/completion_provider.rs | 12 +++++++++++-
crates/agent_ui/src/text_thread_editor.rs  | 13 ++++++++++---
2 files changed, 21 insertions(+), 4 deletions(-)

Detailed changes

crates/agent_ui/src/completion_provider.rs 🔗

@@ -2050,7 +2050,17 @@ fn selection_ranges(
 
         selections
             .into_iter()
-            .map(|s| snapshot.anchor_after(s.start)..snapshot.anchor_before(s.end))
+            .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)
+            })
             .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)?;

crates/agent_ui/src/text_thread_editor.rs 🔗

@@ -1509,9 +1509,16 @@ impl TextThreadEditor {
                     .selections
                     .all_adjusted(&editor.display_snapshot(cx))
                     .into_iter()
-                    .filter_map(|s| {
-                        (!s.is_empty())
-                            .then(|| snapshot.anchor_after(s.start)..snapshot.anchor_before(s.end))
+                    .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)
                     })
                     .collect::<Vec<_>>()
             });