edit prediction: Refine the stealth mode (#25599)
Release Notes: - N/A --------- Co-authored-by: Agus Zubiaga <agus@zed.dev>
This commit is contained in:
parent
c0b6d86c41
commit
bab65011b4
2 changed files with 119 additions and 64 deletions
|
@ -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,24 +6010,6 @@ impl Editor {
|
|||
|
||||
const POLE_WIDTH: Pixels = px(2.);
|
||||
|
||||
let mut element = v_flex()
|
||||
.items_end()
|
||||
.child(
|
||||
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),
|
||||
)
|
||||
.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;
|
||||
|
@ -6009,8 +6018,41 @@ impl Editor {
|
|||
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()
|
||||
.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()
|
||||
.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 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.))
|
||||
.child(
|
||||
if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
|
||||
.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(
|
||||
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(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()),
|
||||
Some(IconSize::XSmall.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(
|
||||
|
|
|
@ -3,7 +3,6 @@ pub(crate) mod autoscroll;
|
|||
pub(crate) mod scroll_amount;
|
||||
|
||||
use crate::editor_settings::{ScrollBeyondLastLine, ScrollbarAxes};
|
||||
use crate::EditPredictionPreview;
|
||||
use crate::{
|
||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||
hover_popover::hide_hover,
|
||||
|
@ -496,14 +495,8 @@ impl Editor {
|
|||
hide_hover(self, cx);
|
||||
let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
|
||||
|
||||
if let EditPredictionPreview::Active {
|
||||
previous_scroll_position,
|
||||
} = &mut self.edit_prediction_preview
|
||||
{
|
||||
if !autoscroll {
|
||||
previous_scroll_position.take();
|
||||
}
|
||||
}
|
||||
self.edit_prediction_preview
|
||||
.set_previous_scroll_position(None);
|
||||
|
||||
self.scroll_manager.set_scroll_position(
|
||||
scroll_position,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue