@@ -494,13 +494,33 @@ pub enum MenuInlineCompletionsPolicy {
pub enum EditPredictionPreview {
/// Modifier is not pressed
- Inactive,
+ Inactive { released_too_fast: bool },
/// Modifier pressed
Active {
+ since: Instant,
previous_scroll_position: Option<ScrollAnchor>,
},
}
+impl EditPredictionPreview {
+ pub fn released_too_fast(&self) -> bool {
+ match self {
+ EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
+ EditPredictionPreview::Active { .. } => false,
+ }
+ }
+
+ pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
+ if let EditPredictionPreview::Active {
+ previous_scroll_position,
+ ..
+ } = self
+ {
+ *previous_scroll_position = scroll_position;
+ }
+ }
+}
+
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
struct EditorActionId(usize);
@@ -1395,7 +1415,9 @@ impl Editor {
edit_prediction_provider: None,
active_inline_completion: None,
stale_inline_completion_in_menu: None,
- edit_prediction_preview: EditPredictionPreview::Inactive,
+ edit_prediction_preview: EditPredictionPreview::Inactive {
+ released_too_fast: false,
+ },
inline_diagnostics_enabled: mode == EditorMode::Full,
inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
@@ -5123,13 +5145,14 @@ impl Editor {
);
self.clear_row_highlights::<EditPredictionPreview>();
- self.edit_prediction_preview = EditPredictionPreview::Active {
- previous_scroll_position: None,
- };
+ self.edit_prediction_preview
+ .set_previous_scroll_position(None);
} else {
- self.edit_prediction_preview = EditPredictionPreview::Active {
- previous_scroll_position: Some(position_map.snapshot.scroll_anchor),
- };
+ self.edit_prediction_preview
+ .set_previous_scroll_position(Some(
+ position_map.snapshot.scroll_anchor,
+ ));
+
self.highlight_rows::<EditPredictionPreview>(
target..target,
cx.theme().colors().editor_highlighted_line_background,
@@ -5389,10 +5412,11 @@ impl Editor {
if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
if matches!(
self.edit_prediction_preview,
- EditPredictionPreview::Inactive
+ EditPredictionPreview::Inactive { .. }
) {
self.edit_prediction_preview = EditPredictionPreview::Active {
previous_scroll_position: None,
+ since: Instant::now(),
};
self.update_visible_inline_completion(window, cx);
@@ -5400,6 +5424,7 @@ impl Editor {
}
} else if let EditPredictionPreview::Active {
previous_scroll_position,
+ since,
} = self.edit_prediction_preview
{
if let (Some(previous_scroll_position), Some(position_map)) =
@@ -5413,7 +5438,9 @@ impl Editor {
);
}
- self.edit_prediction_preview = EditPredictionPreview::Inactive;
+ self.edit_prediction_preview = EditPredictionPreview::Inactive {
+ released_too_fast: since.elapsed() < Duration::from_millis(200),
+ };
self.clear_row_highlights::<EditPredictionPreview>();
self.update_visible_inline_completion(window, cx);
cx.notify();
@@ -5983,34 +6010,49 @@ impl Editor {
const POLE_WIDTH: Pixels = px(2.);
+ let line_layout =
+ line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
+ let target_column = target_display_point.column() as usize;
+
+ let target_x = line_layout.x_for_index(target_column);
+ let target_y =
+ (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
+
+ let flag_on_right = target_x < text_bounds.size.width / 2.;
+
+ let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
+ border_color.l += 0.001;
+
let mut element = v_flex()
.items_end()
- .child(
+ .when(flag_on_right, |el| el.items_start())
+ .child(if flag_on_right {
+ self.render_edit_prediction_line_popover("Jump", None, window, cx)?
+ .rounded_bl(px(0.))
+ .rounded_tl(px(0.))
+ .border_l_2()
+ .border_color(border_color)
+ } else {
self.render_edit_prediction_line_popover("Jump", None, window, cx)?
.rounded_br(px(0.))
.rounded_tr(px(0.))
- .border_r_2(),
- )
- .child(
- div()
- .w(POLE_WIDTH)
- .bg(Editor::edit_prediction_callout_popover_border_color(cx))
- .h(line_height),
- )
+ .border_r_2()
+ .border_color(border_color)
+ })
+ .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
.into_any();
let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
- let line_layout =
- line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
- let target_column = target_display_point.column() as usize;
-
- let target_x = line_layout.x_for_index(target_column);
- let target_y =
- (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
-
let mut origin = scrolled_content_origin + point(target_x, target_y)
- - point(size.width - POLE_WIDTH, size.height - line_height);
+ - point(
+ if flag_on_right {
+ POLE_WIDTH
+ } else {
+ size.width - POLE_WIDTH
+ },
+ size.height - line_height,
+ );
origin.x = origin.x.max(content_origin.x);
@@ -6499,46 +6541,66 @@ impl Editor {
}
let completion = match &self.active_inline_completion {
- Some(completion) => match &completion.completion {
- InlineCompletion::Move {
- target, snapshot, ..
- } if !self.has_visible_completions_menu() => {
- use text::ToPoint as _;
+ Some(prediction) => {
+ if !self.has_visible_completions_menu() {
+ const RADIUS: Pixels = px(6.);
+ const BORDER_WIDTH: Pixels = px(1.);
return Some(
h_flex()
- .px_2()
- .py_1()
- .gap_2()
.elevation_2(cx)
+ .border(BORDER_WIDTH)
.border_color(cx.theme().colors().border)
- .rounded(px(6.))
+ .rounded(RADIUS)
.rounded_tl(px(0.))
+ .overflow_hidden()
+ .child(div().px_1p5().child(match &prediction.completion {
+ InlineCompletion::Move { target, snapshot } => {
+ use text::ToPoint as _;
+ if target.text_anchor.to_point(&snapshot).row > cursor_point.row
+ {
+ Icon::new(IconName::ZedPredictDown)
+ } else {
+ Icon::new(IconName::ZedPredictUp)
+ }
+ }
+ InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
+ }))
.child(
- if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
- Icon::new(IconName::ZedPredictDown)
- } else {
- Icon::new(IconName::ZedPredictUp)
- },
+ h_flex()
+ .gap_1()
+ .py_1()
+ .px_2()
+ .rounded_r(RADIUS - BORDER_WIDTH)
+ .border_l_1()
+ .border_color(cx.theme().colors().border)
+ .bg(Self::edit_prediction_line_popover_bg_color(cx))
+ .when(self.edit_prediction_preview.released_too_fast(), |el| {
+ el.child(
+ Label::new("Hold")
+ .size(LabelSize::Small)
+ .line_height_style(LineHeightStyle::UiLabel),
+ )
+ })
+ .child(h_flex().children(ui::render_modifiers(
+ &accept_keystroke?.modifiers,
+ PlatformStyle::platform(),
+ Some(Color::Default),
+ Some(IconSize::XSmall.rems().into()),
+ false,
+ ))),
)
- .child(Label::new("Hold").size(LabelSize::Small))
- .child(h_flex().children(ui::render_modifiers(
- &accept_keystroke?.modifiers,
- PlatformStyle::platform(),
- Some(Color::Default),
- Some(IconSize::Small.rems().into()),
- false,
- )))
.into_any(),
);
}
- _ => self.render_edit_prediction_cursor_popover_preview(
- completion,
+
+ self.render_edit_prediction_cursor_popover_preview(
+ prediction,
cursor_point,
style,
cx,
- )?,
- },
+ )?
+ }
None if is_refreshing => match &self.stale_inline_completion_in_menu {
Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(