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 {
|
pub enum EditPredictionPreview {
|
||||||
/// Modifier is not pressed
|
/// Modifier is not pressed
|
||||||
Inactive,
|
Inactive { released_too_fast: bool },
|
||||||
/// Modifier pressed
|
/// Modifier pressed
|
||||||
Active {
|
Active {
|
||||||
|
since: Instant,
|
||||||
previous_scroll_position: Option<ScrollAnchor>,
|
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)]
|
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
|
||||||
struct EditorActionId(usize);
|
struct EditorActionId(usize);
|
||||||
|
|
||||||
|
@ -1395,7 +1415,9 @@ impl Editor {
|
||||||
edit_prediction_provider: None,
|
edit_prediction_provider: None,
|
||||||
active_inline_completion: None,
|
active_inline_completion: None,
|
||||||
stale_inline_completion_in_menu: 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,
|
inline_diagnostics_enabled: mode == EditorMode::Full,
|
||||||
inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
|
inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
|
||||||
|
|
||||||
|
@ -5123,13 +5145,14 @@ impl Editor {
|
||||||
);
|
);
|
||||||
self.clear_row_highlights::<EditPredictionPreview>();
|
self.clear_row_highlights::<EditPredictionPreview>();
|
||||||
|
|
||||||
self.edit_prediction_preview = EditPredictionPreview::Active {
|
self.edit_prediction_preview
|
||||||
previous_scroll_position: None,
|
.set_previous_scroll_position(None);
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
self.edit_prediction_preview = EditPredictionPreview::Active {
|
self.edit_prediction_preview
|
||||||
previous_scroll_position: Some(position_map.snapshot.scroll_anchor),
|
.set_previous_scroll_position(Some(
|
||||||
};
|
position_map.snapshot.scroll_anchor,
|
||||||
|
));
|
||||||
|
|
||||||
self.highlight_rows::<EditPredictionPreview>(
|
self.highlight_rows::<EditPredictionPreview>(
|
||||||
target..target,
|
target..target,
|
||||||
cx.theme().colors().editor_highlighted_line_background,
|
cx.theme().colors().editor_highlighted_line_background,
|
||||||
|
@ -5389,10 +5412,11 @@ impl Editor {
|
||||||
if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
|
if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
|
||||||
if matches!(
|
if matches!(
|
||||||
self.edit_prediction_preview,
|
self.edit_prediction_preview,
|
||||||
EditPredictionPreview::Inactive
|
EditPredictionPreview::Inactive { .. }
|
||||||
) {
|
) {
|
||||||
self.edit_prediction_preview = EditPredictionPreview::Active {
|
self.edit_prediction_preview = EditPredictionPreview::Active {
|
||||||
previous_scroll_position: None,
|
previous_scroll_position: None,
|
||||||
|
since: Instant::now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.update_visible_inline_completion(window, cx);
|
self.update_visible_inline_completion(window, cx);
|
||||||
|
@ -5400,6 +5424,7 @@ impl Editor {
|
||||||
}
|
}
|
||||||
} else if let EditPredictionPreview::Active {
|
} else if let EditPredictionPreview::Active {
|
||||||
previous_scroll_position,
|
previous_scroll_position,
|
||||||
|
since,
|
||||||
} = self.edit_prediction_preview
|
} = self.edit_prediction_preview
|
||||||
{
|
{
|
||||||
if let (Some(previous_scroll_position), Some(position_map)) =
|
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.clear_row_highlights::<EditPredictionPreview>();
|
||||||
self.update_visible_inline_completion(window, cx);
|
self.update_visible_inline_completion(window, cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -5983,24 +6010,6 @@ impl Editor {
|
||||||
|
|
||||||
const POLE_WIDTH: Pixels = px(2.);
|
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 =
|
let line_layout =
|
||||||
line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
|
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_column = target_display_point.column() as usize;
|
||||||
|
@ -6009,8 +6018,41 @@ impl Editor {
|
||||||
let target_y =
|
let target_y =
|
||||||
(target_display_point.row().as_f32() * line_height) - scroll_pixel_position.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)
|
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);
|
origin.x = origin.x.max(content_origin.x);
|
||||||
|
|
||||||
|
@ -6499,46 +6541,66 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
let completion = match &self.active_inline_completion {
|
let completion = match &self.active_inline_completion {
|
||||||
Some(completion) => match &completion.completion {
|
Some(prediction) => {
|
||||||
InlineCompletion::Move {
|
if !self.has_visible_completions_menu() {
|
||||||
target, snapshot, ..
|
const RADIUS: Pixels = px(6.);
|
||||||
} if !self.has_visible_completions_menu() => {
|
const BORDER_WIDTH: Pixels = px(1.);
|
||||||
use text::ToPoint as _;
|
|
||||||
|
|
||||||
return Some(
|
return Some(
|
||||||
h_flex()
|
h_flex()
|
||||||
.px_2()
|
|
||||||
.py_1()
|
|
||||||
.gap_2()
|
|
||||||
.elevation_2(cx)
|
.elevation_2(cx)
|
||||||
|
.border(BORDER_WIDTH)
|
||||||
.border_color(cx.theme().colors().border)
|
.border_color(cx.theme().colors().border)
|
||||||
.rounded(px(6.))
|
.rounded(RADIUS)
|
||||||
.rounded_tl(px(0.))
|
.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(
|
.child(
|
||||||
if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
|
h_flex()
|
||||||
Icon::new(IconName::ZedPredictDown)
|
.gap_1()
|
||||||
} else {
|
.py_1()
|
||||||
Icon::new(IconName::ZedPredictUp)
|
.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(),
|
.into_any(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => self.render_edit_prediction_cursor_popover_preview(
|
|
||||||
completion,
|
self.render_edit_prediction_cursor_popover_preview(
|
||||||
|
prediction,
|
||||||
cursor_point,
|
cursor_point,
|
||||||
style,
|
style,
|
||||||
cx,
|
cx,
|
||||||
)?,
|
)?
|
||||||
},
|
}
|
||||||
|
|
||||||
None if is_refreshing => match &self.stale_inline_completion_in_menu {
|
None if is_refreshing => match &self.stale_inline_completion_in_menu {
|
||||||
Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
|
Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
|
||||||
|
|
|
@ -3,7 +3,6 @@ pub(crate) mod autoscroll;
|
||||||
pub(crate) mod scroll_amount;
|
pub(crate) mod scroll_amount;
|
||||||
|
|
||||||
use crate::editor_settings::{ScrollBeyondLastLine, ScrollbarAxes};
|
use crate::editor_settings::{ScrollBeyondLastLine, ScrollbarAxes};
|
||||||
use crate::EditPredictionPreview;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||||
hover_popover::hide_hover,
|
hover_popover::hide_hover,
|
||||||
|
@ -496,14 +495,8 @@ impl Editor {
|
||||||
hide_hover(self, cx);
|
hide_hover(self, cx);
|
||||||
let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
|
let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
|
||||||
|
|
||||||
if let EditPredictionPreview::Active {
|
self.edit_prediction_preview
|
||||||
previous_scroll_position,
|
.set_previous_scroll_position(None);
|
||||||
} = &mut self.edit_prediction_preview
|
|
||||||
{
|
|
||||||
if !autoscroll {
|
|
||||||
previous_scroll_position.take();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.scroll_manager.set_scroll_position(
|
self.scroll_manager.set_scroll_position(
|
||||||
scroll_position,
|
scroll_position,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue