From ec060663022f619b5d8db6dd2bd73bc7f7d5a749 Mon Sep 17 00:00:00 2001
From: d0 <35865489+neiii@users.noreply.github.com>
Date: Fri, 17 Jul 2026 12:41:08 +0100
Subject: [PATCH] outline: Add preview pane to buffer symbols (#61069)
# Objective
- Implement preview pane for buffer symbols, similar to #59863
## Showcase
### Before
### After
---
Release Notes:
- Added a preview pane to the buffer symbols picker
---
Cargo.lock | 1 +
crates/outline/Cargo.toml | 1 +
crates/outline/src/outline.rs | 37 ++++++++++++++++++++++++++++++++---
3 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 1094fced2c..3775ab6b3a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -12560,6 +12560,7 @@ dependencies = [
"lsp",
"menu",
"picker",
+ "picker_preview",
"project",
"rope",
"serde_json",
diff --git a/crates/outline/Cargo.toml b/crates/outline/Cargo.toml
index 8b49b5a287..ba661b36f9 100644
--- a/crates/outline/Cargo.toml
+++ b/crates/outline/Cargo.toml
@@ -18,6 +18,7 @@ fuzzy_nucleo.workspace = true
gpui.workspace = true
language.workspace = true
picker.workspace = true
+picker_preview.workspace = true
settings.workspace = true
theme.workspace = true
theme_settings.workspace = true
diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs
index ffd11e3197..0f22226f89 100644
--- a/crates/outline/src/outline.rs
+++ b/crates/outline/src/outline.rs
@@ -10,8 +10,8 @@ use gpui::{
ParentElement, Point, Rems, Render, Styled, StyledText, Task, TextStyle, WeakEntity, Window,
div, rems,
};
-use language::{Outline, OutlineItem, OutlineSearchEntry};
-use picker::{Picker, PickerDelegate};
+use language::{OffsetRangeExt, Outline, OutlineItem, OutlineSearchEntry};
+use picker::{MatchLocation, Picker, PickerDelegate, PreviewUpdate};
use settings::Settings;
use theme::ActiveTheme;
use theme_settings::ThemeSettings;
@@ -176,9 +176,16 @@ impl OutlineView {
window: &mut Window,
cx: &mut Context,
) -> OutlineView {
+ let project = editor.read(cx).project().cloned();
let delegate = OutlineViewDelegate::new(cx.entity().downgrade(), outline, editor, cx);
let picker = cx.new(|cx| {
- Picker::uniform_list(delegate, window, cx)
+ let picker = if let Some(project) = project {
+ let preview = picker_preview::editor_preview(project, window, cx);
+ Picker::uniform_list_with_preview(delegate, preview, window, cx)
+ } else {
+ Picker::uniform_list(delegate, window, cx)
+ };
+ picker
.max_height(Rems::from_pixels(
window.viewport_size().height * 0.75,
window,
@@ -293,6 +300,30 @@ impl PickerDelegate for OutlineViewDelegate {
self.set_selected_index(ix, true, cx);
}
+ fn try_get_preview_data_for_match(&self, cx: &App) -> Option {
+ let selected_match = self.matches.get(self.selected_match_index)?;
+ let outline_item = self.outline.items.get(selected_match.candidate_id())?;
+ let multi_buffer = self.active_editor.read(cx).buffer().clone();
+ let (buffer, start) = multi_buffer
+ .read(cx)
+ .text_anchor_for_position(outline_item.selection_range.start, cx)?;
+ let (end_buffer, end) = multi_buffer
+ .read(cx)
+ .text_anchor_for_position(outline_item.selection_range.end, cx)?;
+ if buffer != end_buffer {
+ return None;
+ }
+
+ let range = (start..end).to_offset(&buffer.read(cx).text_snapshot());
+ Some(PreviewUpdate::from_buffer(
+ buffer,
+ MatchLocation {
+ anchor_range: start..end,
+ range,
+ },
+ ))
+ }
+
fn update_matches(
&mut self,
query: String,