edit prediction: Use thin cursor for jump preview and gradients instead of ellipsis (#24202)
https://github.com/user-attachments/assets/06e14893-c285-4cea-927c-75e82a378b15 Release Notes: - N/A --------- Co-authored-by: Ben <ben@zed.dev>
This commit is contained in:
+68
-31
@@ -76,14 +76,14 @@ use code_context_menus::{
|
||||
};
|
||||
use git::blame::GitBlame;
|
||||
use gpui::{
|
||||
div, impl_actions, point, prelude::*, pulsating_between, px, relative, size, Action, Animation,
|
||||
AnimationExt, AnyElement, App, AsyncWindowContext, AvailableSpace, Bounds, ClipboardEntry,
|
||||
ClipboardItem, Context, DispatchPhase, ElementId, Entity, EntityInputHandler, EventEmitter,
|
||||
FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla,
|
||||
InteractiveText, KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad, ParentElement,
|
||||
Pixels, Render, SharedString, Size, Styled, StyledText, Subscription, Task, TextStyle,
|
||||
TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
|
||||
WeakFocusHandle, Window,
|
||||
div, impl_actions, linear_color_stop, linear_gradient, point, prelude::*, pulsating_between,
|
||||
px, relative, size, Action, Animation, AnimationExt, AnyElement, App, AsyncWindowContext,
|
||||
AvailableSpace, Bounds, ClipboardEntry, ClipboardItem, Context, DispatchPhase, ElementId,
|
||||
Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId,
|
||||
FontWeight, Global, HighlightStyle, Hsla, InteractiveText, KeyContext, Modifiers, MouseButton,
|
||||
MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, SharedString, Size, Styled,
|
||||
StyledText, Subscription, Task, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle,
|
||||
UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
|
||||
};
|
||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||
use hover_popover::{hide_hover, HoverState};
|
||||
@@ -107,7 +107,7 @@ pub use proposed_changes_editor::{
|
||||
ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
|
||||
};
|
||||
use similar::{ChangeTag, TextDiff};
|
||||
use std::iter::{self, Peekable};
|
||||
use std::iter::Peekable;
|
||||
use task::{ResolvedTask, TaskTemplate, TaskVariables};
|
||||
|
||||
use hover_links::{find_file, HoverLink, HoveredLinkState, InlayHighlight};
|
||||
@@ -466,7 +466,7 @@ pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
|
||||
type CompletionId = usize;
|
||||
|
||||
pub(crate) enum EditDisplayMode {
|
||||
TabAccept,
|
||||
TabAccept(bool),
|
||||
DiffPopover,
|
||||
Inline,
|
||||
}
|
||||
@@ -4953,6 +4953,13 @@ impl Editor {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn is_previewing_inline_completion(&self) -> bool {
|
||||
matches!(
|
||||
self.context_menu.borrow().as_ref(),
|
||||
Some(CodeContextMenu::Completions(menu)) if !menu.is_empty() && menu.previewing_inline_completion
|
||||
)
|
||||
}
|
||||
|
||||
fn update_inline_completion_preview(
|
||||
&mut self,
|
||||
modifiers: &Modifiers,
|
||||
@@ -5117,7 +5124,7 @@ impl Editor {
|
||||
|
||||
let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
|
||||
if provider.show_tab_accept_marker() {
|
||||
EditDisplayMode::TabAccept
|
||||
EditDisplayMode::TabAccept(self.is_previewing_inline_completion())
|
||||
} else {
|
||||
EditDisplayMode::Inline
|
||||
}
|
||||
@@ -5405,10 +5412,12 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn render_edit_prediction_cursor_popover(
|
||||
&self,
|
||||
max_width: Pixels,
|
||||
cursor_point: Point,
|
||||
line_layouts: &[LineWithInvisibles],
|
||||
style: &EditorStyle,
|
||||
accept_keystroke: &gpui::Keystroke,
|
||||
window: &Window,
|
||||
@@ -5456,6 +5465,7 @@ impl Editor {
|
||||
Some(completion) => self.render_edit_prediction_cursor_popover_preview(
|
||||
completion,
|
||||
cursor_point,
|
||||
line_layouts,
|
||||
style,
|
||||
cx,
|
||||
)?,
|
||||
@@ -5464,6 +5474,7 @@ impl Editor {
|
||||
Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
|
||||
stale_completion,
|
||||
cursor_point,
|
||||
line_layouts,
|
||||
style,
|
||||
cx,
|
||||
)?,
|
||||
@@ -5549,6 +5560,7 @@ impl Editor {
|
||||
&self,
|
||||
completion: &InlineCompletionState,
|
||||
cursor_point: Point,
|
||||
line_layouts: &[LineWithInvisibles],
|
||||
style: &EditorStyle,
|
||||
cx: &mut Context<Editor>,
|
||||
) -> Option<Div> {
|
||||
@@ -5644,32 +5656,27 @@ impl Editor {
|
||||
range_around_target,
|
||||
snapshot,
|
||||
} => {
|
||||
let mut highlighted_text = snapshot.highlighted_text_for_range(
|
||||
let highlighted_text = snapshot.highlighted_text_for_range(
|
||||
range_around_target.clone(),
|
||||
None,
|
||||
&style.syntax,
|
||||
);
|
||||
let cursor_color = self.current_user_player_color(cx).cursor;
|
||||
let target_ix =
|
||||
text::ToOffset::to_offset(&target.text_anchor, &snapshot).saturating_sub(
|
||||
text::ToOffset::to_offset(&range_around_target.start, &snapshot),
|
||||
);
|
||||
highlighted_text.highlights = gpui::combine_highlights(
|
||||
highlighted_text.highlights,
|
||||
iter::once((
|
||||
target_ix..target_ix + 1,
|
||||
HighlightStyle {
|
||||
background_color: Some(cursor_color),
|
||||
..Default::default()
|
||||
},
|
||||
)),
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let start_point = range_around_target.start.to_point(&snapshot);
|
||||
let end_point = range_around_target.end.to_point(&snapshot);
|
||||
let ellipsis_before = start_point.column > 0;
|
||||
let ellipsis_after = end_point.column < snapshot.line_len(end_point.row);
|
||||
let target_point = target.text_anchor.to_point(&snapshot);
|
||||
|
||||
let start_column_x =
|
||||
line_layouts[start_point.row as usize].x_for_index(start_point.column as usize);
|
||||
let target_column_x = line_layouts[target_point.row as usize]
|
||||
.x_for_index(target_point.column as usize);
|
||||
let cursor_relative_position = target_column_x - start_column_x;
|
||||
|
||||
let fade_before = start_point.column > 0;
|
||||
let fade_after = end_point.column < snapshot.line_len(end_point.row);
|
||||
|
||||
let background = cx.theme().colors().elevated_surface_background;
|
||||
|
||||
Some(
|
||||
h_flex()
|
||||
@@ -5682,9 +5689,39 @@ impl Editor {
|
||||
.when(!highlighted_text.text.is_empty(), |parent| {
|
||||
parent.child(
|
||||
h_flex()
|
||||
.when(ellipsis_before, |parent| parent.child("…"))
|
||||
.relative()
|
||||
.child(highlighted_text.to_styled_text(&style.text))
|
||||
.when(ellipsis_after, |parent| parent.child("…")),
|
||||
.when(fade_before, |parent| {
|
||||
parent.child(
|
||||
div().absolute().top_0().left_0().w_4().h_full().bg(
|
||||
linear_gradient(
|
||||
90.,
|
||||
linear_color_stop(background, 0.),
|
||||
linear_color_stop(background.opacity(0.), 1.),
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
.when(fade_after, |parent| {
|
||||
parent.child(
|
||||
div().absolute().top_0().right_0().w_4().h_full().bg(
|
||||
linear_gradient(
|
||||
-90.,
|
||||
linear_color_stop(background, 0.),
|
||||
linear_color_stop(background.opacity(0.), 1.),
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
div()
|
||||
.w(px(2.))
|
||||
.h_full()
|
||||
.bg(cursor_color)
|
||||
.absolute()
|
||||
.top_0()
|
||||
.left(cursor_relative_position),
|
||||
),
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -1668,7 +1668,7 @@ impl EditorElement {
|
||||
if let Some(inline_completion) = editor.active_inline_completion.as_ref() {
|
||||
match &inline_completion.completion {
|
||||
InlineCompletion::Edit {
|
||||
display_mode: EditDisplayMode::TabAccept,
|
||||
display_mode: EditDisplayMode::TabAccept(_),
|
||||
..
|
||||
} => padding += INLINE_ACCEPT_SUGGESTION_EM_WIDTHS,
|
||||
_ => {}
|
||||
@@ -3301,6 +3301,7 @@ impl EditorElement {
|
||||
let mut element = editor.render_edit_prediction_cursor_popover(
|
||||
max_width,
|
||||
cursor_point,
|
||||
&line_layouts,
|
||||
style,
|
||||
accept_keystroke.as_ref()?,
|
||||
window,
|
||||
@@ -3686,6 +3687,7 @@ impl EditorElement {
|
||||
let mut element = inline_completion_accept_indicator(
|
||||
"Jump to Edit",
|
||||
Some(IconName::ArrowUp),
|
||||
true,
|
||||
self.editor.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
@@ -3698,6 +3700,7 @@ impl EditorElement {
|
||||
let mut element = inline_completion_accept_indicator(
|
||||
"Jump to Edit",
|
||||
Some(IconName::ArrowDown),
|
||||
true,
|
||||
self.editor.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
@@ -3713,6 +3716,7 @@ impl EditorElement {
|
||||
let mut element = inline_completion_accept_indicator(
|
||||
"Jump to Edit",
|
||||
None,
|
||||
true,
|
||||
self.editor.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
@@ -3764,7 +3768,8 @@ impl EditorElement {
|
||||
}
|
||||
|
||||
match display_mode {
|
||||
EditDisplayMode::TabAccept => {
|
||||
EditDisplayMode::TabAccept(previewing) => {
|
||||
let previewing = *previewing;
|
||||
let range = &edits.first()?.0;
|
||||
let target_display_point = range.end.to_display_point(editor_snapshot);
|
||||
|
||||
@@ -3779,6 +3784,7 @@ impl EditorElement {
|
||||
let mut element = inline_completion_accept_indicator(
|
||||
"Accept",
|
||||
None,
|
||||
!previewing,
|
||||
self.editor.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
@@ -5816,6 +5822,7 @@ fn header_jump_data(
|
||||
fn inline_completion_accept_indicator(
|
||||
label: impl Into<SharedString>,
|
||||
icon: Option<IconName>,
|
||||
show_modifiers: bool,
|
||||
focus_handle: FocusHandle,
|
||||
window: &Window,
|
||||
cx: &App,
|
||||
@@ -5834,11 +5841,13 @@ fn inline_completion_accept_indicator(
|
||||
.text_size(TextSize::XSmall.rems(cx))
|
||||
.text_color(cx.theme().colors().text)
|
||||
.gap_1()
|
||||
.children(ui::render_modifiers(
|
||||
&accept_keystroke.modifiers,
|
||||
PlatformStyle::platform(),
|
||||
Some(Color::Default),
|
||||
))
|
||||
.when(show_modifiers, |parent| {
|
||||
parent.children(ui::render_modifiers(
|
||||
&accept_keystroke.modifiers,
|
||||
PlatformStyle::platform(),
|
||||
Some(Color::Default),
|
||||
))
|
||||
})
|
||||
.child(accept_keystroke.key.clone());
|
||||
|
||||
let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
|
||||
|
||||
Reference in New Issue
Block a user