edit predictions: Cache settings across renders (#24581)
We were reading edit prediction settings too often, causing frames to be dropped. We'll now cache them and update them from `update_visible_inline_completion`. Release Notes: - N/A
This commit is contained in:
parent
973cb916f3
commit
0af048a7cf
10 changed files with 124 additions and 102 deletions
|
@ -1255,7 +1255,7 @@ impl InlineAssistant {
|
|||
editor.scroll_manager.set_forbid_vertical_scroll(true);
|
||||
editor.set_show_scrollbars(false, cx);
|
||||
editor.set_read_only(true);
|
||||
editor.set_show_inline_completions(Some(false), window, cx);
|
||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||
editor.highlight_rows::<DeletedLines>(
|
||||
Anchor::min()..Anchor::max(),
|
||||
cx.theme().status().deleted_background,
|
||||
|
|
|
@ -1345,7 +1345,7 @@ impl InlineAssistant {
|
|||
editor.scroll_manager.set_forbid_vertical_scroll(true);
|
||||
editor.set_show_scrollbars(false, cx);
|
||||
editor.set_read_only(true);
|
||||
editor.set_show_inline_completions(Some(false), window, cx);
|
||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||
editor.highlight_rows::<DeletedLines>(
|
||||
Anchor::min()..Anchor::max(),
|
||||
cx.theme().status().deleted_background,
|
||||
|
|
|
@ -497,6 +497,23 @@ struct InlineCompletionState {
|
|||
invalidation_range: Range<Anchor>,
|
||||
}
|
||||
|
||||
enum EditPredictionSettings {
|
||||
Disabled,
|
||||
Enabled {
|
||||
show_in_menu: bool,
|
||||
preview_requires_modifier: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl EditPredictionSettings {
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
match self {
|
||||
EditPredictionSettings::Disabled => false,
|
||||
EditPredictionSettings::Enabled { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum InlineCompletionHighlight {}
|
||||
|
||||
pub enum MenuInlineCompletionsPolicy {
|
||||
|
@ -683,6 +700,7 @@ pub struct Editor {
|
|||
active_inline_completion: Option<InlineCompletionState>,
|
||||
/// Used to prevent flickering as the user types while the menu is open
|
||||
stale_inline_completion_in_menu: Option<InlineCompletionState>,
|
||||
edit_prediction_settings: EditPredictionSettings,
|
||||
inline_completions_hidden_for_vim_mode: bool,
|
||||
show_inline_completions_override: Option<bool>,
|
||||
menu_inline_completions_policy: MenuInlineCompletionsPolicy,
|
||||
|
@ -1395,6 +1413,7 @@ impl Editor {
|
|||
inline_completions_hidden_for_vim_mode: false,
|
||||
show_inline_completions_override: None,
|
||||
menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
|
||||
edit_prediction_settings: EditPredictionSettings::Disabled,
|
||||
custom_context_menu: None,
|
||||
show_git_blame_gutter: false,
|
||||
show_git_blame_inline: false,
|
||||
|
@ -1530,7 +1549,7 @@ impl Editor {
|
|||
key_context.add("copilot_suggestion");
|
||||
key_context.add("edit_prediction");
|
||||
|
||||
if showing_completions || self.edit_prediction_requires_modifier(cx) {
|
||||
if showing_completions || self.edit_prediction_requires_modifier() {
|
||||
key_context.add(EDIT_PREDICTION_REQUIRES_MODIFIER_KEY_CONTEXT);
|
||||
}
|
||||
}
|
||||
|
@ -1886,23 +1905,14 @@ impl Editor {
|
|||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.show_inline_completions_override.is_some() {
|
||||
self.set_show_inline_completions(None, window, cx);
|
||||
self.set_show_edit_predictions(None, window, cx);
|
||||
} else {
|
||||
let cursor = self.selections.newest_anchor().head();
|
||||
if let Some((buffer, cursor_buffer_position)) =
|
||||
self.buffer.read(cx).text_anchor_for_position(cursor, cx)
|
||||
{
|
||||
let show_inline_completions = !self.should_show_inline_completions_in_buffer(
|
||||
&buffer,
|
||||
cursor_buffer_position,
|
||||
cx,
|
||||
);
|
||||
self.set_show_inline_completions(Some(show_inline_completions), window, cx);
|
||||
}
|
||||
let show_edit_predictions = !self.edit_predictions_enabled();
|
||||
self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_show_inline_completions(
|
||||
pub fn set_show_edit_predictions(
|
||||
&mut self,
|
||||
show_edit_predictions: Option<bool>,
|
||||
window: &mut Window,
|
||||
|
@ -3019,7 +3029,7 @@ impl Editor {
|
|||
}
|
||||
|
||||
let trigger_in_words =
|
||||
this.show_edit_predictions_in_menu(cx) || !had_active_inline_completion;
|
||||
this.show_edit_predictions_in_menu() || !had_active_inline_completion;
|
||||
this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
|
||||
linked_editing_ranges::refresh_linked_ranges(this, window, cx);
|
||||
this.refresh_inline_completion(true, false, window, cx);
|
||||
|
@ -3912,7 +3922,7 @@ impl Editor {
|
|||
*editor.context_menu.borrow_mut() =
|
||||
Some(CodeContextMenu::Completions(menu));
|
||||
|
||||
if editor.show_edit_predictions_in_menu(cx) {
|
||||
if editor.show_edit_predictions_in_menu() {
|
||||
editor.update_visible_inline_completion(window, cx);
|
||||
} else {
|
||||
editor.discard_inline_completion(false, cx);
|
||||
|
@ -3926,7 +3936,7 @@ impl Editor {
|
|||
// If it was already hidden and we don't show inline
|
||||
// completions in the menu, we should also show the
|
||||
// inline-completion when available.
|
||||
if was_hidden && editor.show_edit_predictions_in_menu(cx) {
|
||||
if was_hidden && editor.show_edit_predictions_in_menu() {
|
||||
editor.update_visible_inline_completion(window, cx);
|
||||
}
|
||||
}
|
||||
|
@ -3976,7 +3986,7 @@ impl Editor {
|
|||
|
||||
let entries = completions_menu.entries.borrow();
|
||||
let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
|
||||
if self.show_edit_predictions_in_menu(cx) {
|
||||
if self.show_edit_predictions_in_menu() {
|
||||
self.discard_inline_completion(true, cx);
|
||||
}
|
||||
let candidate_id = mat.candidate_id;
|
||||
|
@ -4668,7 +4678,7 @@ impl Editor {
|
|||
}
|
||||
|
||||
if !user_requested
|
||||
&& (!self.should_show_inline_completions_in_buffer(&buffer, cursor_buffer_position, cx)
|
||||
&& (!self.should_show_edit_predictions()
|
||||
|| !self.is_focused(window)
|
||||
|| buffer.read(cx).is_empty())
|
||||
{
|
||||
|
@ -4687,58 +4697,79 @@ impl Editor {
|
|||
Some(())
|
||||
}
|
||||
|
||||
pub fn should_show_inline_completions(&self, cx: &App) -> bool {
|
||||
let cursor = self.selections.newest_anchor().head();
|
||||
if let Some((buffer, cursor_position)) =
|
||||
self.buffer.read(cx).text_anchor_for_position(cursor, cx)
|
||||
{
|
||||
self.should_show_inline_completions_in_buffer(&buffer, cursor_position, cx)
|
||||
} else {
|
||||
false
|
||||
fn show_edit_predictions_in_menu(&self) -> bool {
|
||||
match self.edit_prediction_settings {
|
||||
EditPredictionSettings::Disabled => false,
|
||||
EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
|
||||
}
|
||||
}
|
||||
|
||||
fn edit_prediction_requires_modifier(&self, cx: &App) -> bool {
|
||||
let cursor = self.selections.newest_anchor().head();
|
||||
|
||||
self.buffer
|
||||
.read(cx)
|
||||
.text_anchor_for_position(cursor, cx)
|
||||
.map(|(buffer, _)| {
|
||||
all_language_settings(buffer.read(cx).file(), cx).inline_completions_preview_mode()
|
||||
== InlineCompletionPreviewMode::WhenHoldingModifier
|
||||
})
|
||||
.unwrap_or(false)
|
||||
pub fn edit_predictions_enabled(&self) -> bool {
|
||||
match self.edit_prediction_settings {
|
||||
EditPredictionSettings::Disabled => false,
|
||||
EditPredictionSettings::Enabled { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn should_show_inline_completions_in_buffer(
|
||||
fn edit_prediction_requires_modifier(&self) -> bool {
|
||||
match self.edit_prediction_settings {
|
||||
EditPredictionSettings::Disabled => false,
|
||||
EditPredictionSettings::Enabled {
|
||||
preview_requires_modifier,
|
||||
..
|
||||
} => preview_requires_modifier,
|
||||
}
|
||||
}
|
||||
|
||||
fn edit_prediction_settings_at_position(
|
||||
&self,
|
||||
buffer: &Entity<Buffer>,
|
||||
buffer_position: language::Anchor,
|
||||
cx: &App,
|
||||
) -> bool {
|
||||
if !self.snippet_stack.is_empty() {
|
||||
return false;
|
||||
) -> EditPredictionSettings {
|
||||
if self.mode != EditorMode::Full
|
||||
|| !self.show_inline_completions_override.unwrap_or(true)
|
||||
|| self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
|
||||
{
|
||||
return EditPredictionSettings::Disabled;
|
||||
}
|
||||
|
||||
if self.inline_completions_disabled_in_scope(buffer, buffer_position, cx) {
|
||||
return false;
|
||||
}
|
||||
let buffer = buffer.read(cx);
|
||||
|
||||
if let Some(show_inline_completions) = self.show_inline_completions_override {
|
||||
show_inline_completions
|
||||
} else {
|
||||
let buffer = buffer.read(cx);
|
||||
self.mode == EditorMode::Full
|
||||
&& language_settings(
|
||||
buffer.language_at(buffer_position).map(|l| l.name()),
|
||||
buffer.file(),
|
||||
cx,
|
||||
)
|
||||
.show_edit_predictions
|
||||
let file = buffer.file();
|
||||
|
||||
if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
|
||||
return EditPredictionSettings::Disabled;
|
||||
};
|
||||
|
||||
let by_provider = matches!(
|
||||
self.menu_inline_completions_policy,
|
||||
MenuInlineCompletionsPolicy::ByProvider
|
||||
);
|
||||
|
||||
let show_in_menu = by_provider
|
||||
&& EditorSettings::get_global(cx).show_edit_predictions_in_menu
|
||||
&& self
|
||||
.edit_prediction_provider
|
||||
.as_ref()
|
||||
.map_or(false, |provider| {
|
||||
provider.provider.show_completions_in_menu()
|
||||
});
|
||||
|
||||
let preview_requires_modifier = all_language_settings(file, cx)
|
||||
.inline_completions_preview_mode()
|
||||
== InlineCompletionPreviewMode::WhenHoldingModifier;
|
||||
|
||||
EditPredictionSettings::Enabled {
|
||||
show_in_menu,
|
||||
preview_requires_modifier,
|
||||
}
|
||||
}
|
||||
|
||||
fn should_show_edit_predictions(&self) -> bool {
|
||||
self.snippet_stack.is_empty() && self.edit_predictions_enabled()
|
||||
}
|
||||
|
||||
pub fn inline_completions_enabled(&self, cx: &App) -> bool {
|
||||
let cursor = self.selections.newest_anchor().head();
|
||||
if let Some((buffer, cursor_position)) =
|
||||
|
@ -4781,9 +4812,7 @@ impl Editor {
|
|||
let cursor = self.selections.newest_anchor().head();
|
||||
let (buffer, cursor_buffer_position) =
|
||||
self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
|
||||
if self.inline_completions_hidden_for_vim_mode
|
||||
|| !self.should_show_inline_completions_in_buffer(&buffer, cursor_buffer_position, cx)
|
||||
{
|
||||
if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -4889,7 +4918,7 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
|
||||
if self.show_edit_predictions_in_menu(cx) {
|
||||
if self.show_edit_predictions_in_menu() {
|
||||
self.hide_context_menu(window, cx);
|
||||
}
|
||||
|
||||
|
@ -5076,14 +5105,10 @@ impl Editor {
|
|||
/// Returns true when we're displaying the inline completion popover below the cursor
|
||||
/// like we are not previewing and the LSP autocomplete menu is visible
|
||||
/// or we are in `when_holding_modifier` mode.
|
||||
pub fn inline_completion_visible_in_cursor_popover(
|
||||
&self,
|
||||
has_completion: bool,
|
||||
cx: &App,
|
||||
) -> bool {
|
||||
pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
|
||||
if self.previewing_inline_completion
|
||||
|| !self.show_edit_predictions_in_menu(cx)
|
||||
|| !self.should_show_inline_completions(cx)
|
||||
|| !self.show_edit_predictions_in_menu()
|
||||
|| !self.edit_predictions_enabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -5092,7 +5117,7 @@ impl Editor {
|
|||
return true;
|
||||
}
|
||||
|
||||
has_completion && self.edit_prediction_requires_modifier(cx)
|
||||
has_completion && self.edit_prediction_requires_modifier()
|
||||
}
|
||||
|
||||
fn handle_modifiers_changed(
|
||||
|
@ -5102,7 +5127,7 @@ impl Editor {
|
|||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.show_edit_predictions_in_menu(cx) {
|
||||
if self.show_edit_predictions_in_menu() {
|
||||
let accept_binding =
|
||||
AcceptEditPredictionBinding::resolve(self.focus_handle(cx), window);
|
||||
if let Some(accept_keystroke) = accept_binding.keystroke() {
|
||||
|
@ -5140,10 +5165,11 @@ impl Editor {
|
|||
let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
|
||||
let excerpt_id = cursor.excerpt_id;
|
||||
|
||||
let show_in_menu = self.show_edit_predictions_in_menu(cx);
|
||||
let show_in_menu = self.show_edit_predictions_in_menu();
|
||||
let completions_menu_has_precedence = !show_in_menu
|
||||
&& (self.context_menu.borrow().is_some()
|
||||
|| (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
|
||||
|
||||
if completions_menu_has_precedence
|
||||
|| !offset_selection.is_empty()
|
||||
|| self
|
||||
|
@ -5160,11 +5186,22 @@ impl Editor {
|
|||
}
|
||||
|
||||
self.take_active_inline_completion(cx);
|
||||
let provider = self.edit_prediction_provider()?;
|
||||
let Some(provider) = self.edit_prediction_provider() else {
|
||||
self.edit_prediction_settings = EditPredictionSettings::Disabled;
|
||||
return None;
|
||||
};
|
||||
|
||||
let (buffer, cursor_buffer_position) =
|
||||
self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
|
||||
|
||||
self.edit_prediction_settings =
|
||||
self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
|
||||
|
||||
if !self.edit_prediction_settings.is_enabled() {
|
||||
self.discard_inline_completion(false, cx);
|
||||
return None;
|
||||
}
|
||||
|
||||
let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
|
||||
let edits = inline_completion
|
||||
.edits
|
||||
|
@ -5223,8 +5260,7 @@ impl Editor {
|
|||
snapshot,
|
||||
}
|
||||
} else {
|
||||
let show_completions_in_buffer = !self
|
||||
.inline_completion_visible_in_cursor_popover(true, cx)
|
||||
let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
|
||||
&& !self.inline_completions_hidden_for_vim_mode;
|
||||
if show_completions_in_buffer {
|
||||
if edits
|
||||
|
@ -5300,19 +5336,6 @@ impl Editor {
|
|||
Some(self.edit_prediction_provider.as_ref()?.provider.clone())
|
||||
}
|
||||
|
||||
fn show_edit_predictions_in_menu(&self, cx: &App) -> bool {
|
||||
let by_provider = matches!(
|
||||
self.menu_inline_completions_policy,
|
||||
MenuInlineCompletionsPolicy::ByProvider
|
||||
);
|
||||
|
||||
by_provider
|
||||
&& EditorSettings::get_global(cx).show_edit_predictions_in_menu
|
||||
&& self
|
||||
.edit_prediction_provider()
|
||||
.map_or(false, |provider| provider.show_completions_in_menu())
|
||||
}
|
||||
|
||||
fn render_code_actions_indicator(
|
||||
&self,
|
||||
_style: &EditorStyle,
|
||||
|
|
|
@ -3088,10 +3088,9 @@ impl EditorElement {
|
|||
|
||||
{
|
||||
let editor = self.editor.read(cx);
|
||||
if editor.inline_completion_visible_in_cursor_popover(
|
||||
editor.has_active_inline_completion(),
|
||||
cx,
|
||||
) {
|
||||
if editor
|
||||
.edit_prediction_visible_in_cursor_popover(editor.has_active_inline_completion())
|
||||
{
|
||||
height_above_menu +=
|
||||
editor.edit_prediction_cursor_popover_height() + POPOVER_Y_PADDING;
|
||||
edit_prediction_popover_visible = true;
|
||||
|
@ -3557,7 +3556,7 @@ impl EditorElement {
|
|||
let editor = self.editor.read(cx);
|
||||
let active_inline_completion = editor.active_inline_completion.as_ref()?;
|
||||
|
||||
if editor.inline_completion_visible_in_cursor_popover(true, cx) {
|
||||
if editor.edit_prediction_visible_in_cursor_popover(true) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ impl FeedbackModal {
|
|||
);
|
||||
editor.set_show_gutter(false, cx);
|
||||
editor.set_show_indent_guides(false, cx);
|
||||
editor.set_show_inline_completions(Some(false), window, cx);
|
||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||
editor.set_vertical_scroll_margin(5, cx);
|
||||
editor.set_use_modal_editing(false);
|
||||
editor.set_soft_wrap();
|
||||
|
|
|
@ -611,7 +611,7 @@ impl InlineCompletionButton {
|
|||
.unwrap_or(true),
|
||||
)
|
||||
};
|
||||
self.editor_show_predictions = editor.should_show_inline_completions(cx);
|
||||
self.editor_show_predictions = editor.edit_predictions_enabled();
|
||||
self.edit_prediction_provider = editor.edit_prediction_provider();
|
||||
self.language = language.cloned();
|
||||
self.file = file;
|
||||
|
|
|
@ -708,7 +708,7 @@ impl LspLogView {
|
|||
editor.set_text(log_contents, window, cx);
|
||||
editor.move_to_end(&MoveToEnd, window, cx);
|
||||
editor.set_read_only(true);
|
||||
editor.set_show_inline_completions(Some(false), window, cx);
|
||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
|
||||
editor
|
||||
});
|
||||
|
@ -751,7 +751,7 @@ impl LspLogView {
|
|||
);
|
||||
editor.set_text(server_info, window, cx);
|
||||
editor.set_read_only(true);
|
||||
editor.set_show_inline_completions(Some(false), window, cx);
|
||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
|
||||
editor
|
||||
});
|
||||
|
|
|
@ -563,7 +563,7 @@ impl PromptLibrary {
|
|||
editor.set_text(prompt_metadata.title.unwrap_or_default(), window, cx);
|
||||
if prompt_id.is_built_in() {
|
||||
editor.set_read_only(true);
|
||||
editor.set_show_inline_completions(Some(false), window, cx);
|
||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||
}
|
||||
editor
|
||||
});
|
||||
|
@ -578,7 +578,7 @@ impl PromptLibrary {
|
|||
let mut editor = Editor::for_buffer(buffer, None, window, cx);
|
||||
if prompt_id.is_built_in() {
|
||||
editor.set_read_only(true);
|
||||
editor.set_show_inline_completions(Some(false), window, cx);
|
||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||
}
|
||||
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
|
||||
editor.set_show_gutter(false, cx);
|
||||
|
|
|
@ -104,7 +104,7 @@ impl Render for QuickActionBar {
|
|||
let git_blame_inline_enabled = editor.git_blame_inline_enabled();
|
||||
let show_git_blame_gutter = editor.show_git_blame_gutter();
|
||||
let auto_signature_help_enabled = editor.auto_signature_help_enabled(cx);
|
||||
let show_inline_completions = editor.should_show_inline_completions(cx);
|
||||
let show_edit_predictions = editor.edit_predictions_enabled();
|
||||
let inline_completion_enabled = editor.inline_completions_enabled(cx);
|
||||
|
||||
(
|
||||
|
@ -114,7 +114,7 @@ impl Render for QuickActionBar {
|
|||
git_blame_inline_enabled,
|
||||
show_git_blame_gutter,
|
||||
auto_signature_help_enabled,
|
||||
show_inline_completions,
|
||||
show_edit_predictions,
|
||||
inline_completion_enabled,
|
||||
)
|
||||
};
|
||||
|
|
|
@ -279,7 +279,7 @@ impl RateCompletionModal {
|
|||
editor.set_show_runnables(false, cx);
|
||||
editor.set_show_wrap_guides(false, cx);
|
||||
editor.set_show_indent_guides(false, cx);
|
||||
editor.set_show_inline_completions(Some(false), window, cx);
|
||||
editor.set_show_edit_predictions(Some(false), window, cx);
|
||||
editor.set_placeholder_text("Add your feedback…", cx);
|
||||
if focus {
|
||||
cx.focus_self(window);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue