diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index a73ba371ed95a1c21b6af0fda68318940e85b8f9..cad517599feea2a81868ca9a90e4facdd9b15295 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -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, ) -> Option
{ @@ -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::>(); 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), + ), ) }), ) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 3cdb198eecdeb1b13d3de790f18bd1825ce17b74..d81ad1441553c6afa1b4d493592c1b8fbe493f22 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -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, icon: Option, + 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.) };