Show loading state for predictions (#23172)
Release Notes: - N/A --------- Co-authored-by: Thorsten <thorsten@zed.dev> Co-authored-by: Danilo Leal <daniloleal09@gmail.com> Co-authored-by: Agus Zubiaga <hi@aguz.me>
This commit is contained in:
parent
bf75b33464
commit
da8e65b3e5
2 changed files with 113 additions and 40 deletions
|
@ -1,8 +1,8 @@
|
|||
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
use gpui::{
|
||||
div, px, uniform_list, AnyElement, BackgroundExecutor, Div, FontWeight, ListSizingBehavior,
|
||||
Model, ScrollStrategy, SharedString, Size, StrikethroughStyle, StyledText,
|
||||
UniformListScrollHandle, ViewContext, WeakView,
|
||||
div, pulsating_between, px, uniform_list, Animation, AnimationExt, AnyElement,
|
||||
BackgroundExecutor, Div, FontWeight, ListSizingBehavior, Model, ScrollStrategy, SharedString,
|
||||
Size, StrikethroughStyle, StyledText, UniformListScrollHandle, ViewContext, WeakView,
|
||||
};
|
||||
use language::Buffer;
|
||||
use language::{CodeLabel, Documentation};
|
||||
|
@ -10,6 +10,8 @@ use lsp::LanguageServerId;
|
|||
use multi_buffer::{Anchor, ExcerptId};
|
||||
use ordered_float::OrderedFloat;
|
||||
use project::{CodeAction, Completion, TaskSourceKind};
|
||||
use settings::Settings;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cmp::{min, Reverse},
|
||||
|
@ -333,7 +335,6 @@ impl CompletionsMenu {
|
|||
entries[0] = hint;
|
||||
}
|
||||
_ => {
|
||||
self.selected_item += 1;
|
||||
entries.insert(0, hint);
|
||||
}
|
||||
}
|
||||
|
@ -461,10 +462,7 @@ impl CompletionsMenu {
|
|||
|
||||
len
|
||||
}
|
||||
CompletionEntry::InlineCompletionHint(InlineCompletionMenuHint {
|
||||
provider_name,
|
||||
..
|
||||
}) => provider_name.len(),
|
||||
CompletionEntry::InlineCompletionHint(hint) => hint.label().chars().count(),
|
||||
})
|
||||
.map(|(ix, _)| ix);
|
||||
drop(completions);
|
||||
|
@ -488,6 +486,12 @@ impl CompletionsMenu {
|
|||
.enumerate()
|
||||
.map(|(ix, mat)| {
|
||||
let item_ix = start_ix + ix;
|
||||
let buffer_font = theme::ThemeSettings::get_global(cx).buffer_font.clone();
|
||||
let base_label = h_flex()
|
||||
.gap_1()
|
||||
.child(div().font(buffer_font.clone()).child("Zed AI"))
|
||||
.child(div().px_0p5().child("/").opacity(0.2));
|
||||
|
||||
match mat {
|
||||
CompletionEntry::Match(mat) => {
|
||||
let candidate_id = mat.candidate_id;
|
||||
|
@ -571,20 +575,57 @@ impl CompletionsMenu {
|
|||
.end_slot::<Label>(documentation_label),
|
||||
)
|
||||
}
|
||||
CompletionEntry::InlineCompletionHint(InlineCompletionMenuHint {
|
||||
provider_name,
|
||||
..
|
||||
}) => div().min_w(px(250.)).max_w(px(500.)).child(
|
||||
CompletionEntry::InlineCompletionHint(
|
||||
hint @ InlineCompletionMenuHint::None,
|
||||
) => div().min_w(px(250.)).max_w(px(500.)).child(
|
||||
ListItem::new("inline-completion")
|
||||
.inset(true)
|
||||
.toggle_state(item_ix == selected_item)
|
||||
.start_slot(Icon::new(IconName::ZedPredict))
|
||||
.child(
|
||||
StyledText::new(format!(
|
||||
"{} Completion",
|
||||
SharedString::new_static(provider_name)
|
||||
))
|
||||
.with_highlights(&style.text, None),
|
||||
base_label.child(
|
||||
StyledText::new(hint.label())
|
||||
.with_highlights(&style.text, None),
|
||||
),
|
||||
),
|
||||
),
|
||||
CompletionEntry::InlineCompletionHint(
|
||||
hint @ InlineCompletionMenuHint::Loading,
|
||||
) => div().min_w(px(250.)).max_w(px(500.)).child(
|
||||
ListItem::new("inline-completion")
|
||||
.inset(true)
|
||||
.toggle_state(item_ix == selected_item)
|
||||
.start_slot(Icon::new(IconName::ZedPredict))
|
||||
.child(base_label.child({
|
||||
let text_style = style.text.clone();
|
||||
StyledText::new(hint.label())
|
||||
.with_highlights(&text_style, None)
|
||||
.with_animation(
|
||||
"pulsating-label",
|
||||
Animation::new(Duration::from_secs(1))
|
||||
.repeat()
|
||||
.with_easing(pulsating_between(0.4, 0.8)),
|
||||
move |text, delta| {
|
||||
let mut text_style = text_style.clone();
|
||||
text_style.color =
|
||||
text_style.color.opacity(delta);
|
||||
text.with_highlights(&text_style, None)
|
||||
},
|
||||
)
|
||||
})),
|
||||
),
|
||||
CompletionEntry::InlineCompletionHint(
|
||||
hint @ InlineCompletionMenuHint::Loaded { .. },
|
||||
) => div().min_w(px(250.)).max_w(px(500.)).child(
|
||||
ListItem::new("inline-completion")
|
||||
.inset(true)
|
||||
.toggle_state(item_ix == selected_item)
|
||||
.start_slot(Icon::new(IconName::ZedPredict))
|
||||
.child(
|
||||
base_label.child(
|
||||
StyledText::new(hint.label())
|
||||
.with_highlights(&style.text, None),
|
||||
),
|
||||
)
|
||||
.on_click(cx.listener(move |editor, _event, cx| {
|
||||
cx.stop_propagation();
|
||||
|
@ -641,19 +682,20 @@ impl CompletionsMenu {
|
|||
Documentation::Undocumented => return None,
|
||||
}
|
||||
}
|
||||
CompletionEntry::InlineCompletionHint(hint) => match &hint.text {
|
||||
InlineCompletionText::Edit { text, highlights } => div()
|
||||
.mx_1()
|
||||
.rounded(px(6.))
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.child(
|
||||
gpui::StyledText::new(text.clone())
|
||||
.with_highlights(&style.text, highlights.clone()),
|
||||
),
|
||||
InlineCompletionText::Move(text) => div().child(text.clone()),
|
||||
},
|
||||
CompletionEntry::InlineCompletionHint(InlineCompletionMenuHint::Loaded { text }) => {
|
||||
match text {
|
||||
InlineCompletionText::Edit { text, highlights } => div()
|
||||
.mx_1()
|
||||
.rounded_md()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.child(
|
||||
gpui::StyledText::new(text.clone())
|
||||
.with_highlights(&style.text, highlights.clone()),
|
||||
),
|
||||
InlineCompletionText::Move(text) => div().child(text.clone()),
|
||||
}
|
||||
}
|
||||
CompletionEntry::InlineCompletionHint(_) => return None,
|
||||
};
|
||||
|
||||
Some(
|
||||
|
|
|
@ -459,9 +459,21 @@ pub fn make_suggestion_styles(cx: &WindowContext) -> InlineCompletionStyles {
|
|||
type CompletionId = usize;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct InlineCompletionMenuHint {
|
||||
provider_name: &'static str,
|
||||
text: InlineCompletionText,
|
||||
enum InlineCompletionMenuHint {
|
||||
Loading,
|
||||
Loaded { text: InlineCompletionText },
|
||||
None,
|
||||
}
|
||||
|
||||
impl InlineCompletionMenuHint {
|
||||
pub fn label(&self) -> &'static str {
|
||||
match self {
|
||||
InlineCompletionMenuHint::Loading | InlineCompletionMenuHint::Loaded { .. } => {
|
||||
"Edit Prediction"
|
||||
}
|
||||
InlineCompletionMenuHint::None => "No Prediction",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -3828,6 +3840,26 @@ impl Editor {
|
|||
) -> Option<Task<std::result::Result<(), anyhow::Error>>> {
|
||||
use language::ToOffset as _;
|
||||
|
||||
{
|
||||
let context_menu = self.context_menu.borrow();
|
||||
if let CodeContextMenu::Completions(menu) = context_menu.as_ref()? {
|
||||
let entries = menu.entries.borrow();
|
||||
let entry = entries.get(item_ix.unwrap_or(menu.selected_item));
|
||||
match entry {
|
||||
Some(CompletionEntry::InlineCompletionHint(
|
||||
InlineCompletionMenuHint::Loading,
|
||||
)) => return Some(Task::ready(Ok(()))),
|
||||
Some(CompletionEntry::InlineCompletionHint(InlineCompletionMenuHint::None)) => {
|
||||
drop(entries);
|
||||
drop(context_menu);
|
||||
self.context_menu_next(&Default::default(), cx);
|
||||
return Some(Task::ready(Ok(())));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let completions_menu =
|
||||
if let CodeContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
|
||||
menu
|
||||
|
@ -3838,7 +3870,7 @@ impl Editor {
|
|||
let entries = completions_menu.entries.borrow();
|
||||
let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
|
||||
let mat = match mat {
|
||||
CompletionEntry::InlineCompletionHint { .. } => {
|
||||
CompletionEntry::InlineCompletionHint(_) => {
|
||||
self.accept_inline_completion(&AcceptInlineCompletion, cx);
|
||||
cx.stop_propagation();
|
||||
return Some(Task::ready(Ok(())));
|
||||
|
@ -4912,8 +4944,8 @@ impl Editor {
|
|||
&mut self,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<InlineCompletionMenuHint> {
|
||||
let provider = self.inline_completion_provider()?;
|
||||
if self.has_active_inline_completion() {
|
||||
let provider_name = self.inline_completion_provider()?.display_name();
|
||||
let editor_snapshot = self.snapshot(cx);
|
||||
|
||||
let text = match &self.active_inline_completion.as_ref()?.completion {
|
||||
|
@ -4930,12 +4962,11 @@ impl Editor {
|
|||
}
|
||||
};
|
||||
|
||||
Some(InlineCompletionMenuHint {
|
||||
provider_name,
|
||||
text,
|
||||
})
|
||||
Some(InlineCompletionMenuHint::Loaded { text })
|
||||
} else if provider.is_refreshing(cx) {
|
||||
Some(InlineCompletionMenuHint::Loading)
|
||||
} else {
|
||||
None
|
||||
Some(InlineCompletionMenuHint::None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue