Rework context insertion UX (#12360)

- Confirming a completion now runs the command immediately
- Hitting `enter` on a line with a command now runs it
- The output of commands gets folded away and replaced with a custom
placeholder
- Eliminated ambient context

<img width="1588" alt="image"
src="https://github.com/zed-industries/zed/assets/482957/b1927a45-52d6-4634-acc9-2ee539c1d89a">

Release Notes:

- N/A

---------

Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2024-05-28 01:44:54 +02:00 committed by GitHub
parent 20f37f0647
commit 7e3ab9acc9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 1148 additions and 1534 deletions

View file

@ -1,11 +1,12 @@
use super::{SlashCommand, SlashCommandCleanup, SlashCommandInvocation};
use super::{SlashCommand, SlashCommandOutput};
use crate::prompts::PromptLibrary;
use anyhow::{anyhow, Context, Result};
use futures::channel::oneshot;
use fuzzy::StringMatchCandidate;
use gpui::{AppContext, Task};
use gpui::{AppContext, Task, WeakView};
use language::LspAdapterDelegate;
use std::sync::{atomic::AtomicBool, Arc};
use ui::{prelude::*, ButtonLike, ElevationIndex};
use workspace::Workspace;
pub(crate) struct PromptSlashCommand {
library: Arc<PromptLibrary>,
@ -26,6 +27,10 @@ impl SlashCommand for PromptSlashCommand {
"insert a prompt from the library".into()
}
fn tooltip_text(&self) -> String {
"insert prompt".into()
}
fn requires_argument(&self) -> bool {
true
}
@ -64,32 +69,43 @@ impl SlashCommand for PromptSlashCommand {
fn run(
self: Arc<Self>,
title: Option<&str>,
_workspace: WeakView<Workspace>,
_delegate: Arc<dyn LspAdapterDelegate>,
cx: &mut AppContext,
) -> SlashCommandInvocation {
cx: &mut WindowContext,
) -> Task<Result<SlashCommandOutput>> {
let Some(title) = title else {
return SlashCommandInvocation {
output: Task::ready(Err(anyhow!("missing prompt name"))),
invalidated: oneshot::channel().1,
cleanup: SlashCommandCleanup::default(),
};
return Task::ready(Err(anyhow!("missing prompt name")));
};
let library = self.library.clone();
let title = title.to_string();
let output = cx.background_executor().spawn(async move {
let prompt = library
.prompts()
.into_iter()
.find(|prompt| &prompt.1.title().to_string() == &title)
.with_context(|| format!("no prompt found with title {:?}", title))?
.1;
Ok(prompt.body())
let title = SharedString::from(title.to_string());
let prompt = cx.background_executor().spawn({
let title = title.clone();
async move {
let prompt = library
.prompts()
.into_iter()
.map(|prompt| (prompt.1.title(), prompt))
.find(|(t, _)| t == &title)
.with_context(|| format!("no prompt found with title {:?}", title))?
.1;
anyhow::Ok(prompt.1.body())
}
});
SlashCommandInvocation {
output,
invalidated: oneshot::channel().1,
cleanup: SlashCommandCleanup::default(),
}
cx.foreground_executor().spawn(async move {
let prompt = prompt.await?;
Ok(SlashCommandOutput {
text: prompt,
render_placeholder: Arc::new(move |id, unfold, _cx| {
ButtonLike::new(id)
.style(ButtonStyle::Filled)
.layer(ElevationIndex::ElevatedSurface)
.child(Icon::new(IconName::Library))
.child(Label::new(title.clone()))
.on_click(move |_, cx| unfold(cx))
.into_any_element()
}),
})
})
}
}