Cancel assists on escape

This commit is contained in:
Nathan Sobo 2023-05-26 14:49:27 -06:00
parent 80080a43e4
commit 8f6e67f440
2 changed files with 54 additions and 20 deletions

View file

@ -198,7 +198,8 @@
{ {
"context": "ContextEditor > Editor", "context": "ContextEditor > Editor",
"bindings": { "bindings": {
"cmd-enter": "assistant::Assist" "cmd-enter": "assistant::Assist",
"escape": "assistant::CancelLastAssist"
} }
}, },
{ {

View file

@ -1,23 +1,24 @@
use crate::{stream_completion, OpenAIRequest, RequestMessage, Role}; use crate::{stream_completion, OpenAIRequest, RequestMessage, Role};
use editor::{Editor, ExcerptRange, MultiBuffer}; use editor::{Editor, MultiBuffer};
use futures::StreamExt; use futures::StreamExt;
use gpui::{ use gpui::{
actions, elements::*, Action, AppContext, Entity, ModelHandle, Subscription, View, ViewContext, actions, elements::*, Action, AppContext, Entity, ModelHandle, Subscription, Task, View,
ViewHandle, WeakViewHandle, WindowContext, ViewContext, ViewHandle, WeakViewHandle, WindowContext,
}; };
use language::{language_settings::SoftWrap, Anchor, Buffer}; use language::{language_settings::SoftWrap, Anchor, Buffer};
use std::sync::Arc; use std::sync::Arc;
use util::ResultExt; use util::{post_inc, ResultExt, TryFutureExt};
use workspace::{ use workspace::{
dock::{DockPosition, Panel}, dock::{DockPosition, Panel},
item::Item, item::Item,
pane, Pane, Workspace, pane, Pane, Workspace,
}; };
actions!(assistant, [NewContext, Assist]); actions!(assistant, [NewContext, Assist, CancelLastAssist]);
pub fn init(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) {
cx.add_action(ContextEditor::assist); cx.add_action(ContextEditor::assist);
cx.add_action(ContextEditor::cancel_last_assist);
} }
pub enum AssistantPanelEvent { pub enum AssistantPanelEvent {
@ -203,6 +204,13 @@ impl Panel for AssistantPanel {
struct ContextEditor { struct ContextEditor {
messages: Vec<Message>, messages: Vec<Message>,
editor: ViewHandle<Editor>, editor: ViewHandle<Editor>,
completion_count: usize,
pending_completions: Vec<PendingCompletion>,
}
struct PendingCompletion {
id: usize,
task: Task<Option<()>>,
} }
impl ContextEditor { impl ContextEditor {
@ -230,7 +238,12 @@ impl ContextEditor {
editor editor
}); });
Self { messages, editor } Self {
messages,
editor,
completion_count: 0,
pending_completions: Vec::new(),
}
} }
fn assist(&mut self, _: &Assist, cx: &mut ViewContext<Self>) { fn assist(&mut self, _: &Assist, cx: &mut ViewContext<Self>) {
@ -265,22 +278,42 @@ impl ContextEditor {
); );
}); });
}); });
cx.spawn(|_, mut cx| async move { let task = cx.spawn(|this, mut cx| {
let mut messages = stream.await?; async move {
let mut messages = stream.await?;
while let Some(message) = messages.next().await { while let Some(message) = messages.next().await {
let mut message = message?; let mut message = message?;
if let Some(choice) = message.choices.pop() { if let Some(choice) = message.choices.pop() {
content.update(&mut cx, |content, cx| { content.update(&mut cx, |content, cx| {
let text: Arc<str> = choice.delta.content?.into(); let text: Arc<str> = choice.delta.content?.into();
content.edit([(content.len()..content.len(), text)], None, cx); content.edit([(content.len()..content.len(), text)], None, cx);
Some(()) Some(())
}); });
}
} }
this.update(&mut cx, |this, _| {
this.pending_completions
.retain(|completion| completion.id != this.completion_count);
})
.ok();
anyhow::Ok(())
} }
anyhow::Ok(()) .log_err()
}) });
.detach_and_log_err(cx);
self.pending_completions.push(PendingCompletion {
id: post_inc(&mut self.completion_count),
task,
});
}
}
fn cancel_last_assist(&mut self, _: &CancelLastAssist, cx: &mut ViewContext<Self>) {
if self.pending_completions.pop().is_none() {
cx.propagate_action();
} }
} }
} }