Open multiple definitions in a multibuffer instead of opening the files directly

This commit is contained in:
Kay Simmons 2023-01-20 13:28:13 -08:00
parent be2c601176
commit 2e37c0ea4a

View file

@ -62,7 +62,7 @@ pub use multi_buffer::{
}; };
use multi_buffer::{MultiBufferChunks, ToOffsetUtf16}; use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use project::{FormatTrigger, LocationLink, Project, ProjectPath, ProjectTransaction}; use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
use scroll::{ use scroll::{
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide, autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
}; };
@ -5012,13 +5012,15 @@ impl Editor {
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) { ) {
let pane = workspace.active_pane().clone(); let pane = workspace.active_pane().clone();
for definition in definitions { // If there is one definition, just open it directly
if let [definition] = definitions.as_slice() {
let range = definition let range = definition
.target .target
.range .range
.to_offset(definition.target.buffer.read(cx)); .to_offset(definition.target.buffer.read(cx));
let target_editor_handle = workspace.open_project_item(definition.target.buffer, cx); let target_editor_handle =
workspace.open_project_item(definition.target.buffer.clone(), cx);
target_editor_handle.update(cx, |target_editor, cx| { target_editor_handle.update(cx, |target_editor, cx| {
// When selecting a definition in a different buffer, disable the nav history // When selecting a definition in a different buffer, disable the nav history
// to avoid creating a history entry at the previous cursor location. // to avoid creating a history entry at the previous cursor location.
@ -5031,6 +5033,28 @@ impl Editor {
pane.update(cx, |pane, _| pane.enable_history()); pane.update(cx, |pane, _| pane.enable_history());
}); });
} else {
let replica_id = editor_handle.read(cx).replica_id(cx);
let title = definitions
.iter()
.find(|definition| definition.origin.is_some())
.and_then(|definition| {
definition.origin.as_ref().map(|origin| {
let buffer = origin.buffer.read(cx);
format!(
"Definitions for {}",
buffer
.text_for_range(origin.range.clone())
.collect::<String>()
)
})
})
.unwrap_or("Definitions".to_owned());
let locations = definitions
.into_iter()
.map(|definition| definition.target)
.collect();
Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
} }
} }
@ -5051,26 +5075,52 @@ impl Editor {
let project = workspace.project().clone(); let project = workspace.project().clone();
let references = project.update(cx, |project, cx| project.references(&buffer, head, cx)); let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
Some(cx.spawn(|workspace, mut cx| async move { Some(cx.spawn(|workspace, mut cx| async move {
let mut locations = references.await?; let locations = references.await?;
if locations.is_empty() { if locations.is_empty() {
return Ok(()); return Ok(());
} }
workspace.update(&mut cx, |workspace, cx| {
let title = locations
.first()
.as_ref()
.map(|location| {
let buffer = location.buffer.read(cx);
format!(
"References to `{}`",
buffer
.text_for_range(location.range.clone())
.collect::<String>()
)
})
.unwrap();
Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx);
});
Ok(())
}))
}
/// Opens a multibuffer with the given project locations in it
pub fn open_locations_in_multibuffer(
workspace: &mut Workspace,
mut locations: Vec<Location>,
replica_id: ReplicaId,
title: String,
cx: &mut ViewContext<Workspace>,
) {
// If there are multiple definitions, open them in a multibuffer
locations.sort_by_key(|location| location.buffer.id()); locations.sort_by_key(|location| location.buffer.id());
let mut locations = locations.into_iter().peekable(); let mut locations = locations.into_iter().peekable();
let mut ranges_to_highlight = Vec::new(); let mut ranges_to_highlight = Vec::new();
let excerpt_buffer = cx.add_model(|cx| { let excerpt_buffer = cx.add_model(|cx| {
let mut symbol_name = None;
let mut multibuffer = MultiBuffer::new(replica_id); let mut multibuffer = MultiBuffer::new(replica_id);
while let Some(location) = locations.next() { while let Some(location) = locations.next() {
let buffer = location.buffer.read(cx); let buffer = location.buffer.read(cx);
let mut ranges_for_buffer = Vec::new(); let mut ranges_for_buffer = Vec::new();
let range = location.range.to_offset(buffer); let range = location.range.to_offset(buffer);
ranges_for_buffer.push(range.clone()); ranges_for_buffer.push(range.clone());
if symbol_name.is_none() {
symbol_name = Some(buffer.text_for_range(range).collect::<String>());
}
while let Some(next_location) = locations.peek() { while let Some(next_location) = locations.peek() {
if next_location.buffer == location.buffer { if next_location.buffer == location.buffer {
@ -5087,14 +5137,15 @@ impl Editor {
ranges_for_buffer, ranges_for_buffer,
1, 1,
cx, cx,
)); ))
} }
multibuffer.with_title(format!("References to `{}`", symbol_name.unwrap()))
multibuffer.with_title(title)
}); });
workspace.update(&mut cx, |workspace, cx| { let editor = cx.add_view(|cx| {
let editor = Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx)); });
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
editor.highlight_background::<Self>( editor.highlight_background::<Self>(
ranges_to_highlight, ranges_to_highlight,
@ -5103,10 +5154,6 @@ impl Editor {
); );
}); });
workspace.add_item(Box::new(editor), cx); workspace.add_item(Box::new(editor), cx);
});
Ok(())
}))
} }
pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> { pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {