edit predictions: Add binding to the prediction toggle (#24468)

This PR primary goal is to add a keybinding to the (ephemeral)
prediction toggle. In doing that, we also standardized the keybinding to
open the status bar menu with it.

Release Notes:

- N/A

---------

Co-authored-by: Bennet Bo Fenner <53836821+bennetbo@users.noreply.github.com>
This commit is contained in:
Danilo Leal 2025-02-07 18:01:39 -03:00 committed by GitHub
parent 07f1b612cf
commit c4bcff1e87
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 215 additions and 162 deletions

View file

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 5C5 3.89543 5.89543 3 7 3H9C10.1046 3 11 3.89543 11 5V6H5V5Z" stroke="black" stroke-width="1.5"/>
<path d="M8 9V11" stroke="black" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="8" cy="9" r="1" fill="black"/>
<rect x="3.75" y="5.75" width="8.5" height="7.5" rx="1.25" stroke="black" stroke-width="1.5" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 452 B

View file

@ -122,7 +122,8 @@
"ctrl-i": "editor::ShowSignatureHelp",
"alt-g b": "editor::ToggleGitBlame",
"menu": "editor::OpenContextMenu",
"shift-f10": "editor::OpenContextMenu"
"shift-f10": "editor::OpenContextMenu",
"ctrl-shift-e": "editor::ToggleEditPrediction"
}
},
{
@ -535,8 +536,7 @@
{
"bindings": {
"ctrl-alt-shift-f": "workspace::FollowNextCollaborator",
"ctrl-alt-i": "zed::DebugElements",
"ctrl-:": "editor::ToggleInlayHints"
"ctrl-alt-i": "zed::DebugElements"
}
},
{
@ -554,7 +554,8 @@
"ctrl-shift-e": "pane::RevealInProjectPanel",
"ctrl-f8": "editor::GoToHunk",
"ctrl-shift-f8": "editor::GoToPrevHunk",
"ctrl-enter": "assistant::InlineAssist"
"ctrl-enter": "assistant::InlineAssist",
"ctrl-:": "editor::ToggleInlayHints"
}
},
{

View file

@ -39,8 +39,8 @@
"cmd-m": "zed::Minimize",
"fn-f": "zed::ToggleFullScreen",
"ctrl-cmd-f": "zed::ToggleFullScreen",
"ctrl-shift-z": "zeta::RateCompletions",
"ctrl-shift-i": "edit_prediction::ToggleMenu"
"ctrl-cmd-z": "zeta::RateCompletions",
"ctrl-cmd-i": "edit_prediction::ToggleMenu"
}
},
{
@ -132,7 +132,8 @@
"cmd-alt-g b": "editor::ToggleGitBlame",
"cmd-i": "editor::ShowSignatureHelp",
"ctrl-f12": "editor::GoToDeclaration",
"alt-ctrl-f12": "editor::GoToDeclarationSplit"
"alt-ctrl-f12": "editor::GoToDeclarationSplit",
"ctrl-cmd-e": "editor::ToggleEditPrediction"
}
},
{
@ -619,8 +620,7 @@
"ctrl-alt-cmd-f": "workspace::FollowNextCollaborator",
// TODO: Move this to a dock open action
"cmd-shift-c": "collab_panel::ToggleFocus",
"cmd-alt-i": "zed::DebugElements",
"ctrl-:": "editor::ToggleInlayHints"
"cmd-alt-i": "zed::DebugElements"
}
},
{
@ -633,7 +633,8 @@
"cmd-shift-e": "pane::RevealInProjectPanel",
"cmd-f8": "editor::GoToHunk",
"cmd-shift-f8": "editor::GoToPrevHunk",
"ctrl-enter": "assistant::InlineAssist"
"ctrl-enter": "assistant::InlineAssist",
"ctrl-:": "editor::ToggleInlayHints"
}
},
{

View file

@ -1,7 +1,11 @@
use anyhow::Result;
use client::UserStore;
use copilot::{Copilot, Status};
use editor::{actions::ShowEditPrediction, scroll::Autoscroll, Editor};
use editor::{
actions::{ShowEditPrediction, ToggleEditPrediction},
scroll::Autoscroll,
Editor,
};
use feature_flags::{
FeatureFlagAppExt, PredictEditsFeatureFlag, PredictEditsRateCompletionsFeatureFlag,
};
@ -44,6 +48,7 @@ struct CopilotErrorToast;
pub struct InlineCompletionButton {
editor_subscription: Option<(Subscription, usize)>,
editor_enabled: Option<bool>,
editor_show_predictions: bool,
editor_focus_handle: Option<FocusHandle>,
language: Option<Arc<Language>>,
file: Option<Arc<dyn File>>,
@ -275,15 +280,29 @@ impl Render for InlineCompletionButton {
);
}
let show_editor_predictions = self.editor_show_predictions;
let icon_button = IconButton::new("zed-predict-pending-button", zeta_icon)
.shape(IconButtonShape::Square)
.when(enabled && !show_editor_predictions, |this| {
this.indicator(Indicator::dot().color(Color::Muted))
.indicator_border_color(Some(cx.theme().colors().status_bar_background))
})
.when(!self.popover_menu_handle.is_deployed(), |element| {
if enabled {
element.tooltip(|window, cx| {
Tooltip::for_action("Edit Prediction", &ToggleMenu, window, cx)
})
} else {
element.tooltip(|window, cx| {
element.tooltip(move |window, cx| {
if enabled {
if show_editor_predictions {
Tooltip::for_action("Edit Prediction", &ToggleMenu, window, cx)
} else {
Tooltip::with_meta(
"Edit Prediction",
Some(&ToggleMenu),
"Hidden For This File",
window,
cx,
)
}
} else {
Tooltip::with_meta(
"Edit Prediction",
Some(&ToggleMenu),
@ -291,8 +310,8 @@ impl Render for InlineCompletionButton {
window,
cx,
)
})
}
}
})
});
let this = cx.entity().clone();
@ -347,6 +366,7 @@ impl InlineCompletionButton {
Self {
editor_subscription: None,
editor_enabled: None,
editor_show_predictions: true,
editor_focus_handle: None,
language: None,
file: None,
@ -384,6 +404,21 @@ impl InlineCompletionButton {
menu = menu.header("Show Edit Predictions For");
if let Some(editor_focus_handle) = self.editor_focus_handle.clone() {
menu = menu.toggleable_entry(
"This File",
self.editor_show_predictions,
IconPosition::Start,
Some(Box::new(ToggleEditPrediction)),
{
let editor_focus_handle = editor_focus_handle.clone();
move |window, cx| {
editor_focus_handle.dispatch_action(&ToggleEditPrediction, window, cx);
}
},
);
}
if let Some(language) = self.language.clone() {
let fs = fs.clone();
let language_enabled =
@ -393,7 +428,7 @@ impl InlineCompletionButton {
menu = menu.toggleable_entry(
language.name(),
language_enabled,
IconPosition::End,
IconPosition::Start,
None,
move |_, cx| {
toggle_show_inline_completions_for_language(language.clone(), fs.clone(), cx)
@ -406,7 +441,7 @@ impl InlineCompletionButton {
menu = menu.toggleable_entry(
"All Files",
globally_enabled,
IconPosition::End,
IconPosition::Start,
None,
move |_, cx| toggle_inline_completions_globally(fs.clone(), cx),
);
@ -422,7 +457,7 @@ impl InlineCompletionButton {
// TODO: We want to add something later that communicates whether
// the current project is open-source.
ContextMenuEntry::new("Share Training Data")
.toggleable(IconPosition::End, data_collection.is_enabled())
.toggleable(IconPosition::Start, data_collection.is_enabled())
.documentation_aside(|_| {
Label::new(indoc!{"
Help us improve our open model by sharing data from open source repositories. \
@ -450,6 +485,8 @@ impl InlineCompletionButton {
menu = menu.item(
ContextMenuEntry::new("Configure Excluded Files")
.icon(IconName::LockOutlined)
.icon_color(Color::Muted)
.documentation_aside(|_| {
Label::new(indoc!{"
Open your settings to add sensitive paths for which Zed will never predict edits."}).into_any_element()
@ -486,7 +523,6 @@ impl InlineCompletionButton {
Some(Box::new(ShowEditPrediction)),
{
let editor_focus_handle = editor_focus_handle.clone();
move |window, cx| {
editor_focus_handle.dispatch_action(&ShowEditPrediction, window, cx);
}
@ -571,6 +607,7 @@ impl InlineCompletionButton {
.unwrap_or(true),
)
};
self.editor_show_predictions = editor.should_show_inline_completions(cx);
self.edit_prediction_provider = editor.edit_prediction_provider();
self.language = language.cloned();
self.file = file;

View file

@ -674,7 +674,8 @@ impl Render for ContextMenu {
let contents = if toggled {
v_flex().flex_none().child(
Icon::new(IconName::Check)
.color(Color::Accent),
.color(Color::Accent)
.size(*icon_size)
)
} else {
v_flex().flex_none().size(

View file

@ -234,6 +234,7 @@ pub enum IconName {
Link,
ListTree,
ListX,
LockOutlined,
MagnifyingGlass,
MailOpen,
Maximize,

View file

@ -213,6 +213,7 @@ impl Render for QuickActionBar {
})
});
let editor_focus_handle = editor.focus_handle(cx);
let editor = editor.downgrade();
let editor_settings_dropdown = {
let vim_mode_enabled = VimModeSetting::get_global(cx).0;
@ -231,20 +232,67 @@ impl Render for QuickActionBar {
.anchor(Corner::TopRight)
.with_handle(self.toggle_settings_handle.clone())
.menu(move |window, cx| {
let menu = ContextMenu::build(window, cx, |mut menu, _, _| {
if supports_inlay_hints {
let menu = ContextMenu::build(window, cx, {
let focus_handle = editor_focus_handle.clone();
|mut menu, _, _| {
menu = menu.context(focus_handle);
if supports_inlay_hints {
menu = menu.toggleable_entry(
"Inlay Hints",
inlay_hints_enabled,
IconPosition::Start,
Some(editor::actions::ToggleInlayHints.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_inlay_hints(
&editor::actions::ToggleInlayHints,
window,
cx,
);
})
.ok();
}
},
);
}
menu = menu.toggleable_entry(
"Inlay Hints",
inlay_hints_enabled,
"Selection Menu",
selection_menu_enabled,
IconPosition::Start,
Some(editor::actions::ToggleInlayHints.boxed_clone()),
Some(editor::actions::ToggleSelectionMenu.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_inlay_hints(
&editor::actions::ToggleInlayHints,
editor.toggle_selection_menu(
&editor::actions::ToggleSelectionMenu,
window,
cx,
)
})
.ok();
}
},
);
menu = menu.toggleable_entry(
"Auto Signature Help",
auto_signature_help_enabled,
IconPosition::Start,
Some(editor::actions::ToggleAutoSignatureHelp.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_auto_signature_help_menu(
&editor::actions::ToggleAutoSignatureHelp,
window,
cx,
);
@ -253,138 +301,96 @@ impl Render for QuickActionBar {
}
},
);
let mut inline_completion_entry = ContextMenuEntry::new("Edit Predictions")
.toggleable(IconPosition::Start, inline_completion_enabled && show_inline_completions)
.disabled(!inline_completion_enabled)
.action(Some(
editor::actions::ToggleEditPrediction.boxed_clone(),
)).handler({
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_inline_completions(
&editor::actions::ToggleEditPrediction,
window,
cx,
);
})
.ok();
}
});
if !inline_completion_enabled {
inline_completion_entry = inline_completion_entry.documentation_aside(|_| {
Label::new("You can't toggle edit predictions for this file as it is within the excluded files list.").into_any_element()
});
}
menu = menu.item(inline_completion_entry);
menu = menu.separator();
menu = menu.toggleable_entry(
"Inline Git Blame",
git_blame_inline_enabled,
IconPosition::Start,
Some(editor::actions::ToggleGitBlameInline.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_git_blame_inline(
&editor::actions::ToggleGitBlameInline,
window,
cx,
)
})
.ok();
}
},
);
menu = menu.toggleable_entry(
"Column Git Blame",
show_git_blame_gutter,
IconPosition::Start,
Some(editor::actions::ToggleGitBlame.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_git_blame(
&editor::actions::ToggleGitBlame,
window,
cx,
)
})
.ok();
}
},
);
menu = menu.separator();
menu = menu.toggleable_entry(
"Vim Mode",
vim_mode_enabled,
IconPosition::Start,
None,
{
move |window, cx| {
let new_value = !vim_mode_enabled;
VimModeSetting::override_global(VimModeSetting(new_value), cx);
window.refresh();
}
},
);
menu
}
menu = menu.toggleable_entry(
"Selection Menu",
selection_menu_enabled,
IconPosition::Start,
Some(editor::actions::ToggleSelectionMenu.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_selection_menu(
&editor::actions::ToggleSelectionMenu,
window,
cx,
)
})
.ok();
}
},
);
menu = menu.toggleable_entry(
"Auto Signature Help",
auto_signature_help_enabled,
IconPosition::Start,
Some(editor::actions::ToggleAutoSignatureHelp.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_auto_signature_help_menu(
&editor::actions::ToggleAutoSignatureHelp,
window,
cx,
);
})
.ok();
}
},
);
let mut inline_completion_entry = ContextMenuEntry::new("Edit Predictions")
.toggleable(IconPosition::Start, inline_completion_enabled && show_inline_completions)
.disabled(!inline_completion_enabled)
.action(Some(
editor::actions::ToggleEditPrediction.boxed_clone(),
)).handler({
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_inline_completions(
&editor::actions::ToggleEditPrediction,
window,
cx,
);
})
.ok();
}
});
if !inline_completion_enabled {
inline_completion_entry = inline_completion_entry.documentation_aside(|_| {
Label::new("You can't toggle edit predictions for this file as it is within the excluded files list.").into_any_element()
});
}
menu = menu.item(inline_completion_entry);
menu = menu.separator();
menu = menu.toggleable_entry(
"Inline Git Blame",
git_blame_inline_enabled,
IconPosition::Start,
Some(editor::actions::ToggleGitBlameInline.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_git_blame_inline(
&editor::actions::ToggleGitBlameInline,
window,
cx,
)
})
.ok();
}
},
);
menu = menu.toggleable_entry(
"Column Git Blame",
show_git_blame_gutter,
IconPosition::Start,
Some(editor::actions::ToggleGitBlame.boxed_clone()),
{
let editor = editor.clone();
move |window, cx| {
editor
.update(cx, |editor, cx| {
editor.toggle_git_blame(
&editor::actions::ToggleGitBlame,
window,
cx,
)
})
.ok();
}
},
);
menu = menu.separator();
menu = menu.toggleable_entry(
"Vim Mode",
vim_mode_enabled,
IconPosition::Start,
None,
{
move |window, cx| {
let new_value = !vim_mode_enabled;
VimModeSetting::override_global(VimModeSetting(new_value), cx);
window.refresh();
}
},
);
menu
});
Some(menu)
})