mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 02:46:43 +00:00
Show "tab Accept" indicator for single line insertions/deletions (#23411)
https://github.com/user-attachments/assets/655f20a9-f22f-4f91-870e-d40b20c8c994 Release Notes: - N/A Co-authored-by: Danilo <danilo@zed.dev>
This commit is contained in:
parent
14cd178ab0
commit
86ff88ae1d
1 changed files with 106 additions and 62 deletions
|
@ -1592,6 +1592,7 @@ impl EditorElement {
|
|||
&self,
|
||||
display_row: DisplayRow,
|
||||
display_snapshot: &DisplaySnapshot,
|
||||
buffer_snapshot: &MultiBufferSnapshot,
|
||||
line_layout: &LineWithInvisibles,
|
||||
crease_trailer: Option<&CreaseTrailerLayout>,
|
||||
em_width: Pixels,
|
||||
|
@ -1617,7 +1618,28 @@ impl EditorElement {
|
|||
let display_point = DisplayPoint::new(display_row, 0);
|
||||
let buffer_row = MultiBufferRow(display_point.to_point(display_snapshot).row);
|
||||
|
||||
let blame = self.editor.read(cx).blame.clone()?;
|
||||
let editor = self.editor.read(cx);
|
||||
let blame = editor.blame.clone()?;
|
||||
let padding = {
|
||||
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 6.;
|
||||
const INLINE_ACCEPT_SUGGESTION_EM_WIDTHS: f32 = 14.;
|
||||
|
||||
let mut padding = INLINE_BLAME_PADDING_EM_WIDTHS;
|
||||
|
||||
if let Some(inline_completion) = editor.active_inline_completion.as_ref() {
|
||||
match &inline_completion.completion {
|
||||
InlineCompletion::Edit(edits)
|
||||
if single_line_edit(&edits, buffer_snapshot).is_some() =>
|
||||
{
|
||||
padding += INLINE_ACCEPT_SUGGESTION_EM_WIDTHS
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
padding * em_width
|
||||
};
|
||||
|
||||
let blame_entry = blame
|
||||
.update(cx, |blame, cx| {
|
||||
blame.blame_for_rows([Some(buffer_row)], cx).next()
|
||||
|
@ -1631,14 +1653,13 @@ impl EditorElement {
|
|||
+ line_height * (display_row.as_f32() - scroll_pixel_position.y / line_height);
|
||||
|
||||
let start_x = {
|
||||
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 6.;
|
||||
|
||||
let line_end = if let Some(crease_trailer) = crease_trailer {
|
||||
crease_trailer.bounds.right()
|
||||
} else {
|
||||
content_origin.x - scroll_pixel_position.x + line_layout.width
|
||||
};
|
||||
let padded_line_end = line_end + em_width * INLINE_BLAME_PADDING_EM_WIDTHS;
|
||||
|
||||
let padded_line_end = line_end + padding;
|
||||
|
||||
let min_column_in_pixels = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
|
@ -3326,49 +3347,23 @@ impl EditorElement {
|
|||
|
||||
match &active_inline_completion.completion {
|
||||
InlineCompletion::Move(target_position) => {
|
||||
let tab_kbd = h_flex()
|
||||
.px_0p5()
|
||||
.font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
|
||||
.text_size(TextSize::XSmall.rems(cx))
|
||||
.text_color(cx.theme().colors().text)
|
||||
.child("tab");
|
||||
|
||||
let icon_container = div().mt(px(2.5)); // For optical alignment
|
||||
|
||||
let container_element = h_flex()
|
||||
.items_center()
|
||||
.py_0p5()
|
||||
.px_1()
|
||||
.gap_1()
|
||||
.bg(cx.theme().colors().text_accent.opacity(0.15))
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().text_accent.opacity(0.8))
|
||||
.rounded_md()
|
||||
.shadow_sm();
|
||||
|
||||
let target_display_point = target_position.to_display_point(editor_snapshot);
|
||||
if target_display_point.row().as_f32() < scroll_top {
|
||||
let mut element = container_element
|
||||
.child(tab_kbd)
|
||||
.child(Label::new("Jump to Edit").size(LabelSize::Small))
|
||||
.child(
|
||||
icon_container
|
||||
.child(Icon::new(IconName::ArrowUp).size(IconSize::Small)),
|
||||
)
|
||||
.into_any();
|
||||
let mut element = inline_completion_tab_indicator(
|
||||
"Jump to Edit",
|
||||
Some(IconName::ArrowUp),
|
||||
cx,
|
||||
);
|
||||
let size = element.layout_as_root(AvailableSpace::min_size(), cx);
|
||||
let offset = point((text_bounds.size.width - size.width) / 2., PADDING_Y);
|
||||
element.prepaint_at(text_bounds.origin + offset, cx);
|
||||
Some(element)
|
||||
} else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
|
||||
let mut element = container_element
|
||||
.child(tab_kbd)
|
||||
.child(Label::new("Jump to Edit").size(LabelSize::Small))
|
||||
.child(
|
||||
icon_container
|
||||
.child(Icon::new(IconName::ArrowDown).size(IconSize::Small)),
|
||||
)
|
||||
.into_any();
|
||||
let mut element = inline_completion_tab_indicator(
|
||||
"Jump to Edit",
|
||||
Some(IconName::ArrowDown),
|
||||
cx,
|
||||
);
|
||||
let size = element.layout_as_root(AvailableSpace::min_size(), cx);
|
||||
let offset = point(
|
||||
(text_bounds.size.width - size.width) / 2.,
|
||||
|
@ -3377,10 +3372,7 @@ impl EditorElement {
|
|||
element.prepaint_at(text_bounds.origin + offset, cx);
|
||||
Some(element)
|
||||
} else {
|
||||
let mut element = container_element
|
||||
.child(tab_kbd)
|
||||
.child(Label::new("Jump to Edit").size(LabelSize::Small))
|
||||
.into_any();
|
||||
let mut element = inline_completion_tab_indicator("Jump to Edit", None, cx);
|
||||
|
||||
let target_line_end = DisplayPoint::new(
|
||||
target_display_point.row(),
|
||||
|
@ -3421,9 +3413,28 @@ impl EditorElement {
|
|||
return None;
|
||||
}
|
||||
|
||||
if !hard_to_spot_single_edit(&edits, &editor_snapshot.buffer_snapshot)
|
||||
&& all_edits_insertions_or_deletions(edits, &editor_snapshot.buffer_snapshot)
|
||||
{
|
||||
if let Some(range) = single_line_edit(&edits, &editor_snapshot.buffer_snapshot) {
|
||||
let mut element = inline_completion_tab_indicator("Accept", None, cx);
|
||||
|
||||
let target_display_point = range.end.to_display_point(editor_snapshot);
|
||||
let target_line_end = DisplayPoint::new(
|
||||
target_display_point.row(),
|
||||
editor_snapshot.line_len(target_display_point.row()),
|
||||
);
|
||||
let origin = self.editor.update(cx, |editor, cx| {
|
||||
editor.display_to_pixel_point(target_line_end, editor_snapshot, cx)
|
||||
})?;
|
||||
|
||||
element.prepaint_as_root(
|
||||
text_bounds.origin + origin + point(PADDING_X, px(0.)),
|
||||
AvailableSpace::min_size(),
|
||||
cx,
|
||||
);
|
||||
|
||||
return Some(element);
|
||||
}
|
||||
|
||||
if all_edits_insertions_or_deletions(edits, &editor_snapshot.buffer_snapshot) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -5203,23 +5214,55 @@ fn header_jump_data(
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if there's a single edit, that's either a single character
|
||||
/// insertion or a single line deletion.
|
||||
fn hard_to_spot_single_edit(
|
||||
edits: &[(Range<Anchor>, String)],
|
||||
fn inline_completion_tab_indicator(
|
||||
label: impl Into<SharedString>,
|
||||
icon: Option<IconName>,
|
||||
cx: &WindowContext,
|
||||
) -> AnyElement {
|
||||
let tab_kbd = h_flex()
|
||||
.px_0p5()
|
||||
.font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
|
||||
.text_size(TextSize::XSmall.rems(cx))
|
||||
.text_color(cx.theme().colors().text)
|
||||
.child("tab");
|
||||
|
||||
let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
|
||||
|
||||
h_flex()
|
||||
.py_0p5()
|
||||
.pl_1()
|
||||
.pr(padding_right)
|
||||
.gap_1()
|
||||
.bg(cx.theme().colors().text_accent.opacity(0.15))
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().text_accent.opacity(0.8))
|
||||
.rounded_md()
|
||||
.shadow_sm()
|
||||
.child(tab_kbd)
|
||||
.child(Label::new(label).size(LabelSize::Small))
|
||||
.when_some(icon, |element, icon| {
|
||||
element.child(
|
||||
div()
|
||||
.mt(px(1.5))
|
||||
.child(Icon::new(icon).size(IconSize::Small)),
|
||||
)
|
||||
})
|
||||
.into_any()
|
||||
}
|
||||
|
||||
fn single_line_edit<'a>(
|
||||
edits: &'a [(Range<Anchor>, String)],
|
||||
snapshot: &MultiBufferSnapshot,
|
||||
) -> bool {
|
||||
if let [(range, new_text)] = edits {
|
||||
match new_text.len() {
|
||||
0 => {
|
||||
let range = range.to_point(&snapshot);
|
||||
range.start.row == range.end.row
|
||||
}
|
||||
1 => true,
|
||||
_ => false,
|
||||
}
|
||||
) -> Option<&'a Range<Anchor>> {
|
||||
let [(range, _)] = edits else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let point_range = range.to_point(&snapshot);
|
||||
if point_range.start.row == point_range.end.row {
|
||||
Some(range)
|
||||
} else {
|
||||
false
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6507,6 +6550,7 @@ impl Element for EditorElement {
|
|||
inline_blame = self.layout_inline_blame(
|
||||
display_row,
|
||||
&snapshot.display_snapshot,
|
||||
&snapshot.buffer_snapshot,
|
||||
line_layout,
|
||||
crease_trailer_layout,
|
||||
em_width,
|
||||
|
|
Loading…
Reference in a new issue