Toggle inline completion menu from keyboard (#23380)

This commit is contained in:
Agus Zubiaga 2025-01-20 19:11:13 -03:00 committed by GitHub
parent 3c0acdea5e
commit 919703e6a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 55 additions and 23 deletions

View file

@ -30,7 +30,9 @@
"ctrl-0": "zed::ResetBufferFontSize", "ctrl-0": "zed::ResetBufferFontSize",
"ctrl-,": "zed::OpenSettings", "ctrl-,": "zed::OpenSettings",
"ctrl-q": "zed::Quit", "ctrl-q": "zed::Quit",
"f11": "zed::ToggleFullScreen" "f11": "zed::ToggleFullScreen",
"ctrl-alt-z": "zeta::RateCompletions",
"ctrl-shift-i": "inline_completion::ToggleMenu"
} }
}, },
{ {

View file

@ -38,7 +38,9 @@
"alt-cmd-h": "zed::HideOthers", "alt-cmd-h": "zed::HideOthers",
"cmd-m": "zed::Minimize", "cmd-m": "zed::Minimize",
"fn-f": "zed::ToggleFullScreen", "fn-f": "zed::ToggleFullScreen",
"ctrl-cmd-f": "zed::ToggleFullScreen" "ctrl-cmd-f": "zed::ToggleFullScreen",
"ctrl-shift-z": "zeta::RateCompletions",
"ctrl-shift-i": "inline_completion::ToggleMenu"
} }
}, },
{ {
@ -68,7 +70,6 @@
"cmd-v": "editor::Paste", "cmd-v": "editor::Paste",
"cmd-z": "editor::Undo", "cmd-z": "editor::Undo",
"cmd-shift-z": "editor::Redo", "cmd-shift-z": "editor::Redo",
"ctrl-shift-z": "zeta::RateCompletions",
"up": "editor::MoveUp", "up": "editor::MoveUp",
"ctrl-up": "editor::MoveToStartOfParagraph", "ctrl-up": "editor::MoveToStartOfParagraph",
"pageup": "editor::MovePageUp", "pageup": "editor::MovePageUp",

View file

@ -18,10 +18,7 @@ use language::{
use settings::{update_settings_file, Settings, SettingsStore}; use settings::{update_settings_file, Settings, SettingsStore};
use std::{path::Path, sync::Arc, time::Duration}; use std::{path::Path, sync::Arc, time::Duration};
use supermaven::{AccountStatus, Supermaven}; use supermaven::{AccountStatus, Supermaven};
use ui::{ use ui::{prelude::*, ButtonLike, Color, Icon, IconWithIndicator, Indicator, PopoverMenuHandle};
ActiveTheme as _, ButtonLike, Color, FluentBuilder as _, Icon, IconWithIndicator, Indicator,
PopoverMenuHandle,
};
use workspace::{ use workspace::{
create_and_open_local_file, create_and_open_local_file,
item::ItemHandle, item::ItemHandle,
@ -36,6 +33,7 @@ use zed_predict_tos::ZedPredictTos;
use zeta::RateCompletionModal; use zeta::RateCompletionModal;
actions!(zeta, [RateCompletions]); actions!(zeta, [RateCompletions]);
actions!(inline_completion, [ToggleMenu]);
const COPILOT_SETTINGS_URL: &str = "https://github.com/settings/copilot"; const COPILOT_SETTINGS_URL: &str = "https://github.com/settings/copilot";
@ -50,7 +48,7 @@ pub struct InlineCompletionButton {
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
user_store: Model<UserStore>, user_store: Model<UserStore>,
zeta_popover_menu_handle: PopoverMenuHandle<ContextMenu>, popover_menu_handle: PopoverMenuHandle<ContextMenu>,
} }
enum SupermavenButtonStatus { enum SupermavenButtonStatus {
@ -118,7 +116,7 @@ impl Render for InlineCompletionButton {
.ok(); .ok();
} }
})) }))
.tooltip(|cx| Tooltip::text("GitHub Copilot", cx)), .tooltip(|cx| Tooltip::for_action("GitHub Copilot", &ToggleMenu, cx)),
); );
} }
let this = cx.view().clone(); let this = cx.view().clone();
@ -135,9 +133,11 @@ impl Render for InlineCompletionButton {
}) })
.anchor(Corner::BottomRight) .anchor(Corner::BottomRight)
.trigger( .trigger(
IconButton::new("copilot-icon", icon) IconButton::new("copilot-icon", icon).tooltip(|cx| {
.tooltip(|cx| Tooltip::text("GitHub Copilot", cx)), Tooltip::for_action("GitHub Copilot", &ToggleMenu, cx)
), }),
)
.with_handle(self.popover_menu_handle.clone()),
) )
} }
@ -170,6 +170,7 @@ impl Render for InlineCompletionButton {
let icon = status.to_icon(); let icon = status.to_icon();
let tooltip_text = status.to_tooltip(); let tooltip_text = status.to_tooltip();
let has_menu = status.has_menu();
let this = cx.view().clone(); let this = cx.view().clone();
let fs = self.fs.clone(); let fs = self.fs.clone();
@ -202,10 +203,14 @@ impl Render for InlineCompletionButton {
_ => None, _ => None,
}) })
.anchor(Corner::BottomRight) .anchor(Corner::BottomRight)
.trigger( .trigger(IconButton::new("supermaven-icon", icon).tooltip(move |cx| {
IconButton::new("supermaven-icon", icon) if has_menu {
.tooltip(move |cx| Tooltip::text(tooltip_text.clone(), cx)), Tooltip::for_action(tooltip_text.clone(), &ToggleMenu, cx)
), } else {
Tooltip::text(tooltip_text.clone(), cx)
}
}))
.with_handle(self.popover_menu_handle.clone()),
); );
} }
@ -254,10 +259,12 @@ impl Render for InlineCompletionButton {
} }
let this = cx.view().clone(); let this = cx.view().clone();
let button = IconButton::new("zeta", IconName::ZedPredict) let button = IconButton::new("zeta", IconName::ZedPredict).when(
.when(!self.zeta_popover_menu_handle.is_deployed(), |button| { !self.popover_menu_handle.is_deployed(),
button.tooltip(|cx| Tooltip::text("Edit Prediction", cx)) |button| {
}); button.tooltip(|cx| Tooltip::for_action("Edit Prediction", &ToggleMenu, cx))
},
);
let is_refreshing = self let is_refreshing = self
.inline_completion_provider .inline_completion_provider
@ -269,7 +276,7 @@ impl Render for InlineCompletionButton {
Some(this.update(cx, |this, cx| this.build_zeta_context_menu(cx))) Some(this.update(cx, |this, cx| this.build_zeta_context_menu(cx)))
}) })
.anchor(Corner::BottomRight) .anchor(Corner::BottomRight)
.with_handle(self.zeta_popover_menu_handle.clone()); .with_handle(self.popover_menu_handle.clone());
if is_refreshing { if is_refreshing {
popover_menu = popover_menu.trigger( popover_menu = popover_menu.trigger(
@ -296,6 +303,7 @@ impl InlineCompletionButton {
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
user_store: Model<UserStore>, user_store: Model<UserStore>,
popover_menu_handle: PopoverMenuHandle<ContextMenu>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
if let Some(copilot) = Copilot::global(cx) { if let Some(copilot) = Copilot::global(cx) {
@ -311,7 +319,7 @@ impl InlineCompletionButton {
language: None, language: None,
file: None, file: None,
inline_completion_provider: None, inline_completion_provider: None,
zeta_popover_menu_handle: PopoverMenuHandle::default(), popover_menu_handle,
workspace, workspace,
fs, fs,
user_store, user_store,
@ -470,6 +478,10 @@ impl InlineCompletionButton {
cx.notify() cx.notify()
} }
pub fn toggle_menu(&mut self, cx: &mut ViewContext<Self>) {
self.popover_menu_handle.toggle(cx);
}
} }
impl StatusItemView for InlineCompletionButton { impl StatusItemView for InlineCompletionButton {
@ -507,6 +519,13 @@ impl SupermavenButtonStatus {
SupermavenButtonStatus::Initializing => "Supermaven initializing".to_string(), SupermavenButtonStatus::Initializing => "Supermaven initializing".to_string(),
} }
} }
fn has_menu(&self) -> bool {
match self {
SupermavenButtonStatus::Ready | SupermavenButtonStatus::NeedsActivation(_) => true,
SupermavenButtonStatus::Errored(_) | SupermavenButtonStatus::Initializing => false,
}
}
} }
async fn configure_disabled_globs( async fn configure_disabled_globs(

View file

@ -145,7 +145,7 @@ impl ContextMenu {
delayed: false, delayed: false,
clicked: false, clicked: false,
_on_blur_subscription, _on_blur_subscription,
keep_open_on_confirm: true, keep_open_on_confirm: false,
}, },
cx, cx,
) )

View file

@ -48,6 +48,7 @@ use std::rc::Rc;
use std::{borrow::Cow, ops::Deref, path::Path, sync::Arc}; use std::{borrow::Cow, ops::Deref, path::Path, sync::Arc};
use terminal_view::terminal_panel::{self, TerminalPanel}; use terminal_view::terminal_panel::{self, TerminalPanel};
use theme::{ActiveTheme, ThemeSettings}; use theme::{ActiveTheme, ThemeSettings};
use ui::PopoverMenuHandle;
use util::markdown::MarkdownString; use util::markdown::MarkdownString;
use util::{asset_str, ResultExt}; use util::{asset_str, ResultExt};
use uuid::Uuid; use uuid::Uuid;
@ -164,15 +165,24 @@ pub fn initialize_workspace(
show_software_emulation_warning_if_needed(specs, cx); show_software_emulation_warning_if_needed(specs, cx);
} }
let popover_menu_handle = PopoverMenuHandle::default();
let inline_completion_button = cx.new_view(|cx| { let inline_completion_button = cx.new_view(|cx| {
inline_completion_button::InlineCompletionButton::new( inline_completion_button::InlineCompletionButton::new(
workspace.weak_handle(), workspace.weak_handle(),
app_state.fs.clone(), app_state.fs.clone(),
app_state.user_store.clone(), app_state.user_store.clone(),
popover_menu_handle.clone(),
cx, cx,
) )
}); });
workspace.register_action({
move |_, _: &inline_completion_button::ToggleMenu, cx| {
popover_menu_handle.toggle(cx);
}
});
let diagnostic_summary = let diagnostic_summary =
cx.new_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx)); cx.new_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx));
let activity_indicator = let activity_indicator =