Open all kinds of files from multi buffers' headers (#20469)

Closes https://github.com/zed-industries/zed/issues/11661

Release Notes:

- Fixed multi buffer headers not able to jump to untitled files
This commit is contained in:
Kirill Bulatov 2024-11-10 10:03:11 +02:00 committed by GitHub
parent ba8f027c18
commit 767a82527a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 61 additions and 142 deletions

View file

@ -128,7 +128,7 @@ use project::{
lsp_store::{FormatTarget, FormatTrigger}, lsp_store::{FormatTarget, FormatTrigger},
project_settings::{GitGutterSetting, ProjectSettings}, project_settings::{GitGutterSetting, ProjectSettings},
CodeAction, Completion, CompletionIntent, DocumentHighlight, InlayHint, Item, Location, CodeAction, Completion, CompletionIntent, DocumentHighlight, InlayHint, Item, Location,
LocationLink, Project, ProjectPath, ProjectTransaction, TaskSourceKind, LocationLink, Project, ProjectTransaction, TaskSourceKind,
}; };
use rand::prelude::*; use rand::prelude::*;
use rpc::{proto::*, ErrorExt}; use rpc::{proto::*, ErrorExt};
@ -12651,60 +12651,6 @@ impl Editor {
}); });
} }
fn jump(
&mut self,
path: ProjectPath,
position: Point,
anchor: language::Anchor,
offset_from_top: u32,
cx: &mut ViewContext<Self>,
) {
let workspace = self.workspace();
cx.spawn(|_, mut cx| async move {
let workspace = workspace.ok_or_else(|| anyhow!("cannot jump without workspace"))?;
let editor = workspace.update(&mut cx, |workspace, cx| {
// Reset the preview item id before opening the new item
workspace.active_pane().update(cx, |pane, cx| {
pane.set_preview_item_id(None, cx);
});
workspace.open_path_preview(path, None, true, true, cx)
})?;
let editor = editor
.await?
.downcast::<Editor>()
.ok_or_else(|| anyhow!("opened item was not an editor"))?
.downgrade();
editor.update(&mut cx, |editor, cx| {
let buffer = editor
.buffer()
.read(cx)
.as_singleton()
.ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
let buffer = buffer.read(cx);
let cursor = if buffer.can_resolve(&anchor) {
language::ToPoint::to_point(&anchor, buffer)
} else {
buffer.clip_point(position, Bias::Left)
};
let nav_history = editor.nav_history.take();
editor.change_selections(
Some(Autoscroll::top_relative(offset_from_top as usize)),
cx,
|s| {
s.select_ranges([cursor..cursor]);
},
);
editor.nav_history = nav_history;
anyhow::Ok(())
})??;
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> { fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
let snapshot = self.buffer.read(cx).read(cx); let snapshot = self.buffer.read(cx).read(cx);
let (_, ranges) = self.text_highlights::<InputComposition>(cx)?; let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;

View file

@ -27,7 +27,6 @@ use crate::{
use client::ParticipantIndex; use client::ParticipantIndex;
use collections::{BTreeMap, HashMap, HashSet}; use collections::{BTreeMap, HashMap, HashSet};
use git::{blame::BlameEntry, diff::DiffHunkStatus, Oid}; use git::{blame::BlameEntry, diff::DiffHunkStatus, Oid};
use gpui::Subscription;
use gpui::{ use gpui::{
anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg, anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg,
transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem, transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem,
@ -38,6 +37,7 @@ use gpui::{
StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, TextStyleRefinement, View, StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, TextStyleRefinement, View,
ViewContext, WeakView, WindowContext, ViewContext, WeakView, WindowContext,
}; };
use gpui::{ClickEvent, Subscription};
use itertools::Itertools; use itertools::Itertools;
use language::{ use language::{
language_settings::{ language_settings::{
@ -2058,7 +2058,6 @@ impl EditorElement {
block: &Block, block: &Block,
available_width: AvailableSpace, available_width: AvailableSpace,
block_id: BlockId, block_id: BlockId,
block_row_start: DisplayRow,
snapshot: &EditorSnapshot, snapshot: &EditorSnapshot,
text_x: Pixels, text_x: Pixels,
rows: &Range<DisplayRow>, rows: &Range<DisplayRow>,
@ -2130,15 +2129,12 @@ impl EditorElement {
next_excerpt, next_excerpt,
show_excerpt_controls, show_excerpt_controls,
starts_new_buffer, starts_new_buffer,
height,
.. ..
} => { } => {
#[derive(Clone)] #[derive(Clone)]
struct JumpData { struct JumpData {
position: Point, position: Point,
anchor: text::Anchor, path: Option<ProjectPath>,
path: ProjectPath,
line_offset_from_top: u32,
} }
let icon_offset = gutter_dimensions.width let icon_offset = gutter_dimensions.width
@ -2169,40 +2165,21 @@ impl EditorElement {
if let Some(next_excerpt) = next_excerpt { if let Some(next_excerpt) = next_excerpt {
let buffer = &next_excerpt.buffer; let buffer = &next_excerpt.buffer;
let range = &next_excerpt.range; let range = &next_excerpt.range;
let jump_data = project::File::from_dyn(buffer.file()).map(|file| { let jump_data = {
let jump_path = ProjectPath { let jump_path =
worktree_id: file.worktree_id(cx), project::File::from_dyn(buffer.file()).map(|file| ProjectPath {
path: file.path.clone(), worktree_id: file.worktree_id(cx),
}; path: file.path.clone(),
});
let jump_anchor = range let jump_anchor = range
.primary .primary
.as_ref() .as_ref()
.map_or(range.context.start, |primary| primary.start); .map_or(range.context.start, |primary| primary.start);
let excerpt_start = range.context.start;
let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
let offset_from_excerpt_start = if jump_anchor == excerpt_start {
0
} else {
let excerpt_start_row =
language::ToPoint::to_point(&jump_anchor, buffer).row;
jump_position.row - excerpt_start_row
};
let line_offset_from_top =
block_row_start.0 + *height + offset_from_excerpt_start
- snapshot
.scroll_anchor
.scroll_position(&snapshot.display_snapshot)
.y as u32;
JumpData { JumpData {
position: jump_position, position: language::ToPoint::to_point(&jump_anchor, buffer),
anchor: jump_anchor,
path: jump_path, path: jump_path,
line_offset_from_top,
} }
}); };
if *starts_new_buffer { if *starts_new_buffer {
let include_root = self let include_root = self
@ -2257,31 +2234,22 @@ impl EditorElement {
}), }),
), ),
) )
.when_some(jump_data, |el, jump_data| { .child(Icon::new(IconName::ArrowUpRight))
el.child(Icon::new(IconName::ArrowUpRight)) .cursor_pointer()
.cursor_pointer() .tooltip(|cx| {
.tooltip(|cx| { Tooltip::for_action("Jump to File", &OpenExcerpts, cx)
Tooltip::for_action( })
"Jump to File", .on_mouse_down(MouseButton::Left, |_, cx| {
&OpenExcerpts, cx.stop_propagation()
cx, })
) .on_click(cx.listener_for(&self.editor, {
}) move |editor, e: &ClickEvent, cx| {
.on_mouse_down(MouseButton::Left, |_, cx| { editor.open_excerpts_common(
cx.stop_propagation() e.down.modifiers.secondary(),
}) cx,
.on_click(cx.listener_for(&self.editor, { );
move |editor, _, cx| { }
editor.jump( })),
jump_data.path.clone(),
jump_data.position,
jump_data.anchor,
jump_data.line_offset_from_top,
cx,
);
}
}))
}),
), ),
); );
if *show_excerpt_controls { if *show_excerpt_controls {
@ -2300,6 +2268,7 @@ impl EditorElement {
); );
} }
} else { } else {
let editor = self.editor.clone();
result = result.child( result = result.child(
h_flex() h_flex()
.id("excerpt header block") .id("excerpt header block")
@ -2320,32 +2289,39 @@ impl EditorElement {
}), }),
) )
.cursor_pointer() .cursor_pointer()
.when_some(jump_data.clone(), |this, jump_data| { .on_click(cx.listener_for(&self.editor, {
this.on_click(cx.listener_for(&self.editor, { move |editor, e: &ClickEvent, cx| {
let path = jump_data.path.clone(); cx.stop_propagation();
move |editor, _, cx| { editor
cx.stop_propagation(); .open_excerpts_common(e.down.modifiers.secondary(), cx);
}
editor.jump( }))
path.clone(), .tooltip(move |cx| {
jump_data.position, let jump_message = format!(
jump_data.anchor, "Jump to {}:L{}",
jump_data.line_offset_from_top, match &jump_data.path {
cx, Some(project_path) =>
); project_path.path.display().to_string(),
} None => {
})) let editor = editor.read(cx);
.tooltip(move |cx| { editor
Tooltip::for_action( .file_at(jump_data.position, cx)
format!( .map(|file| {
"Jump to {}:L{}", file.full_path(cx).display().to_string()
jump_data.path.path.display(), })
jump_data.position.row + 1 .or_else(|| {
), Some(
&OpenExcerpts, editor
cx, .tab_description(0, cx)?
) .to_string(),
}) )
})
.unwrap_or_else(|| "Unknown buffer".to_string())
}
},
jump_data.position.row + 1
);
Tooltip::for_action(jump_message, &OpenExcerpts, cx)
}) })
.child( .child(
h_flex() h_flex()
@ -2480,7 +2456,6 @@ impl EditorElement {
block, block,
AvailableSpace::MinContent, AvailableSpace::MinContent,
block_id, block_id,
row,
snapshot, snapshot,
text_x, text_x,
&rows, &rows,
@ -2526,7 +2501,6 @@ impl EditorElement {
block, block,
width.into(), width.into(),
block_id, block_id,
row,
snapshot, snapshot,
text_x, text_x,
&rows, &rows,
@ -2573,7 +2547,6 @@ impl EditorElement {
&block, &block,
width, width,
focused_block.id, focused_block.id,
rows.end,
snapshot, snapshot,
text_x, text_x,
&rows, &rows,