Cancel workflow step automatically when moving outside <step> tag (#15842)
Also, open edit suggestions automatically as soon as the edit step is resolved. Release Notes: - N/A
This commit is contained in:
parent
7b5fdcee7f
commit
44ae9efb27
3 changed files with 234 additions and 118 deletions
|
@ -8,12 +8,12 @@ use crate::{
|
||||||
SlashCommandCompletionProvider, SlashCommandRegistry,
|
SlashCommandCompletionProvider, SlashCommandRegistry,
|
||||||
},
|
},
|
||||||
terminal_inline_assistant::TerminalInlineAssistant,
|
terminal_inline_assistant::TerminalInlineAssistant,
|
||||||
Assist, ConfirmCommand, Context, ContextEvent, ContextId, ContextStore, CycleMessageRole,
|
Assist, CodegenStatus, ConfirmCommand, Context, ContextEvent, ContextId, ContextStore,
|
||||||
DebugEditSteps, DeployHistory, DeployPromptLibrary, EditSuggestionGroup, InlineAssist,
|
CycleMessageRole, DebugEditSteps, DeployHistory, DeployPromptLibrary, EditSuggestionGroup,
|
||||||
InlineAssistId, InlineAssistant, InsertIntoEditor, MessageStatus, ModelSelector,
|
InlineAssist, InlineAssistId, InlineAssistant, InsertIntoEditor, MessageStatus, ModelSelector,
|
||||||
PendingSlashCommand, PendingSlashCommandStatus, QuoteSelection, RemoteContextMetadata,
|
PendingSlashCommand, PendingSlashCommandStatus, QuoteSelection, RemoteContextMetadata,
|
||||||
SavedContextMetadata, Split, ToggleFocus, ToggleModelSelector, WorkflowStep,
|
ResolvedWorkflowStepEditSuggestions, SavedContextMetadata, Split, ToggleFocus,
|
||||||
WorkflowStepEditSuggestions,
|
ToggleModelSelector, WorkflowStepEditSuggestions,
|
||||||
};
|
};
|
||||||
use crate::{ContextStoreEvent, ShowConfiguration};
|
use crate::{ContextStoreEvent, ShowConfiguration};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
@ -35,8 +35,8 @@ use gpui::{
|
||||||
div, percentage, point, Action, Animation, AnimationExt, AnyElement, AnyView, AppContext,
|
div, percentage, point, Action, Animation, AnimationExt, AnyElement, AnyView, AppContext,
|
||||||
AsyncWindowContext, ClipboardItem, Context as _, DismissEvent, Empty, Entity, EventEmitter,
|
AsyncWindowContext, ClipboardItem, Context as _, DismissEvent, Empty, Entity, EventEmitter,
|
||||||
FocusHandle, FocusableView, FontWeight, InteractiveElement, IntoElement, Model, ParentElement,
|
FocusHandle, FocusableView, FontWeight, InteractiveElement, IntoElement, Model, ParentElement,
|
||||||
Pixels, Render, SharedString, StatefulInteractiveElement, Styled, Subscription, Task,
|
Pixels, ReadGlobal, Render, SharedString, StatefulInteractiveElement, Styled, Subscription,
|
||||||
Transformation, UpdateGlobal, View, ViewContext, VisualContext, WeakView, WindowContext,
|
Task, Transformation, UpdateGlobal, View, ViewContext, VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use indexed_docs::IndexedDocsStore;
|
use indexed_docs::IndexedDocsStore;
|
||||||
use language::{
|
use language::{
|
||||||
|
@ -1295,10 +1295,15 @@ struct ScrollPosition {
|
||||||
cursor: Anchor,
|
cursor: Anchor,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ActiveEditStep {
|
struct StepAssists {
|
||||||
start: language::Anchor,
|
|
||||||
assist_ids: Vec<InlineAssistId>,
|
assist_ids: Vec<InlineAssistId>,
|
||||||
editor: Option<WeakView<Editor>>,
|
editor: WeakView<Editor>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
struct ActiveWorkflowStep {
|
||||||
|
range: Range<language::Anchor>,
|
||||||
|
suggestions: Option<ResolvedWorkflowStepEditSuggestions>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ContextEditor {
|
pub struct ContextEditor {
|
||||||
|
@ -1314,7 +1319,8 @@ pub struct ContextEditor {
|
||||||
pending_slash_command_creases: HashMap<Range<language::Anchor>, CreaseId>,
|
pending_slash_command_creases: HashMap<Range<language::Anchor>, CreaseId>,
|
||||||
pending_slash_command_blocks: HashMap<Range<language::Anchor>, CustomBlockId>,
|
pending_slash_command_blocks: HashMap<Range<language::Anchor>, CustomBlockId>,
|
||||||
_subscriptions: Vec<Subscription>,
|
_subscriptions: Vec<Subscription>,
|
||||||
active_edit_step: Option<ActiveEditStep>,
|
assists_by_step: HashMap<Range<language::Anchor>, StepAssists>,
|
||||||
|
active_workflow_step: Option<ActiveWorkflowStep>,
|
||||||
assistant_panel: WeakView<AssistantPanel>,
|
assistant_panel: WeakView<AssistantPanel>,
|
||||||
error_message: Option<SharedString>,
|
error_message: Option<SharedString>,
|
||||||
}
|
}
|
||||||
|
@ -1372,7 +1378,8 @@ impl ContextEditor {
|
||||||
pending_slash_command_creases: HashMap::default(),
|
pending_slash_command_creases: HashMap::default(),
|
||||||
pending_slash_command_blocks: HashMap::default(),
|
pending_slash_command_blocks: HashMap::default(),
|
||||||
_subscriptions,
|
_subscriptions,
|
||||||
active_edit_step: None,
|
assists_by_step: HashMap::default(),
|
||||||
|
active_workflow_step: None,
|
||||||
assistant_panel,
|
assistant_panel,
|
||||||
error_message: None,
|
error_message: None,
|
||||||
};
|
};
|
||||||
|
@ -1415,8 +1422,9 @@ impl ContextEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_edit_step(&mut self, cx: &mut ViewContext<Self>) -> bool {
|
fn apply_edit_step(&mut self, cx: &mut ViewContext<Self>) -> bool {
|
||||||
if let Some(step) = self.active_edit_step.as_ref() {
|
if let Some(step) = self.active_workflow_step.as_ref() {
|
||||||
let assist_ids = step.assist_ids.clone();
|
if let Some(assists) = self.assists_by_step.get(&step.range) {
|
||||||
|
let assist_ids = assists.assist_ids.clone();
|
||||||
cx.window_context().defer(|cx| {
|
cx.window_context().defer(|cx| {
|
||||||
InlineAssistant::update_global(cx, |assistant, cx| {
|
InlineAssistant::update_global(cx, |assistant, cx| {
|
||||||
for assist_id in assist_ids {
|
for assist_id in assist_ids {
|
||||||
|
@ -1425,7 +1433,10 @@ impl ContextEditor {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
!step.assist_ids.is_empty()
|
!assists.assist_ids.is_empty()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -1462,7 +1473,7 @@ impl ContextEditor {
|
||||||
|
|
||||||
fn debug_edit_steps(&mut self, _: &DebugEditSteps, cx: &mut ViewContext<Self>) {
|
fn debug_edit_steps(&mut self, _: &DebugEditSteps, cx: &mut ViewContext<Self>) {
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
for (i, step) in self.context.read(cx).edit_steps().iter().enumerate() {
|
for (i, step) in self.context.read(cx).workflow_steps().iter().enumerate() {
|
||||||
output.push_str(&format!("Step {}:\n", i + 1));
|
output.push_str(&format!("Step {}:\n", i + 1));
|
||||||
output.push_str(&format!(
|
output.push_str(&format!(
|
||||||
"Content: {}\n",
|
"Content: {}\n",
|
||||||
|
@ -1474,10 +1485,10 @@ impl ContextEditor {
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
));
|
));
|
||||||
match &step.edit_suggestions {
|
match &step.edit_suggestions {
|
||||||
WorkflowStepEditSuggestions::Resolved {
|
WorkflowStepEditSuggestions::Resolved(ResolvedWorkflowStepEditSuggestions {
|
||||||
title,
|
title,
|
||||||
edit_suggestions,
|
edit_suggestions,
|
||||||
} => {
|
}) => {
|
||||||
output.push_str("Resolution:\n");
|
output.push_str("Resolution:\n");
|
||||||
output.push_str(&format!(" {:?}\n", title));
|
output.push_str(&format!(" {:?}\n", title));
|
||||||
output.push_str(&format!(" {:?}\n", edit_suggestions));
|
output.push_str(&format!(" {:?}\n", edit_suggestions));
|
||||||
|
@ -1629,7 +1640,8 @@ impl ContextEditor {
|
||||||
context.save(Some(Duration::from_millis(500)), self.fs.clone(), cx);
|
context.save(Some(Duration::from_millis(500)), self.fs.clone(), cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ContextEvent::EditStepsChanged => {
|
ContextEvent::WorkflowStepsChanged => {
|
||||||
|
self.update_active_workflow_step(cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
ContextEvent::SummaryChanged => {
|
ContextEvent::SummaryChanged => {
|
||||||
|
@ -1902,16 +1914,57 @@ impl ContextEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_active_workflow_step(&mut self, cx: &mut ViewContext<Self>) {
|
fn update_active_workflow_step(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
if self
|
let new_step = self
|
||||||
.workflow_step_for_cursor(cx)
|
.workflow_step_range_for_cursor(cx)
|
||||||
.map(|step| step.tagged_range.start)
|
.as_ref()
|
||||||
!= self.active_edit_step.as_ref().map(|step| step.start)
|
.and_then(|step_range| {
|
||||||
{
|
let workflow_step = self
|
||||||
if let Some(old_active_edit_step) = self.active_edit_step.take() {
|
.context
|
||||||
if let Some(editor) = old_active_edit_step
|
.read(cx)
|
||||||
.editor
|
.workflow_step_for_range(step_range.clone())?;
|
||||||
.and_then(|editor| editor.upgrade())
|
Some(ActiveWorkflowStep {
|
||||||
{
|
range: workflow_step.tagged_range.clone(),
|
||||||
|
suggestions: workflow_step.edit_suggestions.as_resolved().cloned(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if new_step.as_ref() != self.active_workflow_step.as_ref() {
|
||||||
|
if let Some(old_step) = self.active_workflow_step.take() {
|
||||||
|
self.cancel_workflow_step_if_idle(old_step.range, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(new_step) = new_step {
|
||||||
|
self.activate_workflow_step(new_step, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cancel_workflow_step_if_idle(
|
||||||
|
&mut self,
|
||||||
|
step_range: Range<language::Anchor>,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) {
|
||||||
|
let Some(step_assists) = self.assists_by_step.get_mut(&step_range) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(editor) = step_assists.editor.upgrade() else {
|
||||||
|
self.assists_by_step.remove(&step_range);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
InlineAssistant::update_global(cx, |assistant, cx| {
|
||||||
|
step_assists.assist_ids.retain(|assist_id| {
|
||||||
|
match assistant.status_for_assist(*assist_id, cx) {
|
||||||
|
Some(CodegenStatus::Idle) | None => {
|
||||||
|
assistant.finish_assist(*assist_id, true, cx);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if step_assists.assist_ids.is_empty() {
|
||||||
|
self.assists_by_step.remove(&step_range);
|
||||||
self.workspace
|
self.workspace
|
||||||
.update(cx, |workspace, cx| {
|
.update(cx, |workspace, cx| {
|
||||||
if let Some(pane) = workspace.pane_for(&editor) {
|
if let Some(pane) = workspace.pane_for(&editor) {
|
||||||
|
@ -1928,31 +1981,47 @@ impl ContextEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(new_active_step) = self.workflow_step_for_cursor(cx) {
|
fn activate_workflow_step(&mut self, step: ActiveWorkflowStep, cx: &mut ViewContext<Self>) {
|
||||||
let start = new_active_step.tagged_range.start;
|
if let Some(step_assists) = self.assists_by_step.get(&step.range) {
|
||||||
|
if let Some(editor) = step_assists.editor.upgrade() {
|
||||||
|
for assist_id in &step_assists.assist_ids {
|
||||||
|
match InlineAssistant::global(cx).status_for_assist(*assist_id, cx) {
|
||||||
|
Some(CodegenStatus::Idle) | None => {}
|
||||||
|
_ => {
|
||||||
|
self.workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.activate_item(&editor, false, false, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
InlineAssistant::update_global(cx, |assistant, cx| {
|
||||||
|
assistant.scroll_to_assist(*assist_id, cx)
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut editor = None;
|
if let Some(ResolvedWorkflowStepEditSuggestions {
|
||||||
let mut assist_ids = Vec::new();
|
|
||||||
if let WorkflowStepEditSuggestions::Resolved {
|
|
||||||
title,
|
title,
|
||||||
edit_suggestions,
|
edit_suggestions,
|
||||||
} = &new_active_step.edit_suggestions
|
}) = step.suggestions.as_ref()
|
||||||
{
|
{
|
||||||
if let Some((opened_editor, inline_assist_ids)) =
|
if let Some((editor, assist_ids)) =
|
||||||
self.suggest_edits(title.clone(), edit_suggestions.clone(), cx)
|
self.suggest_edits(title.clone(), edit_suggestions.clone(), cx)
|
||||||
{
|
{
|
||||||
editor = Some(opened_editor.downgrade());
|
self.assists_by_step.insert(
|
||||||
assist_ids = inline_assist_ids;
|
step.range.clone(),
|
||||||
|
StepAssists {
|
||||||
|
assist_ids,
|
||||||
|
editor: editor.downgrade(),
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.active_edit_step = Some(ActiveEditStep {
|
self.active_workflow_step = Some(step);
|
||||||
start,
|
|
||||||
assist_ids,
|
|
||||||
editor,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_edits(
|
fn suggest_edits(
|
||||||
|
@ -2436,11 +2505,14 @@ impl ContextEditor {
|
||||||
|
|
||||||
fn render_send_button(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render_send_button(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let focus_handle = self.focus_handle(cx).clone();
|
let focus_handle = self.focus_handle(cx).clone();
|
||||||
let button_text = match self.workflow_step_for_cursor(cx) {
|
let button_text = match self.active_workflow_step.as_ref() {
|
||||||
Some(edit_step) => match &edit_step.edit_suggestions {
|
Some(step) => {
|
||||||
WorkflowStepEditSuggestions::Pending(_) => "Computing Changes...",
|
if step.suggestions.is_none() {
|
||||||
WorkflowStepEditSuggestions::Resolved { .. } => "Apply Changes",
|
"Computing Changes..."
|
||||||
},
|
} else {
|
||||||
|
"Apply Changes"
|
||||||
|
}
|
||||||
|
}
|
||||||
None => "Send",
|
None => "Send",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2482,7 +2554,7 @@ impl ContextEditor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workflow_step_for_cursor<'a>(&'a self, cx: &'a AppContext) -> Option<&'a WorkflowStep> {
|
fn workflow_step_range_for_cursor(&self, cx: &AppContext) -> Option<Range<language::Anchor>> {
|
||||||
let newest_cursor = self
|
let newest_cursor = self
|
||||||
.editor
|
.editor
|
||||||
.read(cx)
|
.read(cx)
|
||||||
|
@ -2493,7 +2565,7 @@ impl ContextEditor {
|
||||||
let context = self.context.read(cx);
|
let context = self.context.read(cx);
|
||||||
let buffer = context.buffer().read(cx);
|
let buffer = context.buffer().read(cx);
|
||||||
|
|
||||||
let edit_steps = context.edit_steps();
|
let edit_steps = context.workflow_steps();
|
||||||
edit_steps
|
edit_steps
|
||||||
.binary_search_by(|step| {
|
.binary_search_by(|step| {
|
||||||
let step_range = step.tagged_range.clone();
|
let step_range = step.tagged_range.clone();
|
||||||
|
@ -2506,7 +2578,7 @@ impl ContextEditor {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.ok()
|
.ok()
|
||||||
.map(|index| &edit_steps[index])
|
.map(|index| edit_steps[index].tagged_range.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -284,7 +284,7 @@ pub enum ContextEvent {
|
||||||
AssistError(String),
|
AssistError(String),
|
||||||
MessagesEdited,
|
MessagesEdited,
|
||||||
SummaryChanged,
|
SummaryChanged,
|
||||||
EditStepsChanged,
|
WorkflowStepsChanged,
|
||||||
StreamedCompletion,
|
StreamedCompletion,
|
||||||
PendingSlashCommandsUpdated {
|
PendingSlashCommandsUpdated {
|
||||||
removed: Vec<Range<language::Anchor>>,
|
removed: Vec<Range<language::Anchor>>,
|
||||||
|
@ -351,21 +351,33 @@ pub struct WorkflowStep {
|
||||||
pub edit_suggestions: WorkflowStepEditSuggestions,
|
pub edit_suggestions: WorkflowStepEditSuggestions,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum WorkflowStepEditSuggestions {
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
Pending(Task<Option<()>>),
|
pub struct ResolvedWorkflowStepEditSuggestions {
|
||||||
Resolved {
|
pub title: String,
|
||||||
title: String,
|
pub edit_suggestions: HashMap<Model<Buffer>, Vec<EditSuggestionGroup>>,
|
||||||
edit_suggestions: HashMap<Model<Buffer>, Vec<EditSuggestionGroup>>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
pub enum WorkflowStepEditSuggestions {
|
||||||
|
Pending(Task<Option<()>>),
|
||||||
|
Resolved(ResolvedWorkflowStepEditSuggestions),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WorkflowStepEditSuggestions {
|
||||||
|
pub fn as_resolved(&self) -> Option<&ResolvedWorkflowStepEditSuggestions> {
|
||||||
|
match self {
|
||||||
|
WorkflowStepEditSuggestions::Resolved(suggestions) => Some(suggestions),
|
||||||
|
WorkflowStepEditSuggestions::Pending(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct EditSuggestionGroup {
|
pub struct EditSuggestionGroup {
|
||||||
pub context_range: Range<language::Anchor>,
|
pub context_range: Range<language::Anchor>,
|
||||||
pub suggestions: Vec<EditSuggestion>,
|
pub suggestions: Vec<EditSuggestion>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum EditSuggestion {
|
pub enum EditSuggestion {
|
||||||
Update {
|
Update {
|
||||||
range: Range<language::Anchor>,
|
range: Range<language::Anchor>,
|
||||||
|
@ -561,10 +573,10 @@ impl Debug for WorkflowStepEditSuggestions {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
WorkflowStepEditSuggestions::Pending(_) => write!(f, "EditStepOperations::Pending"),
|
WorkflowStepEditSuggestions::Pending(_) => write!(f, "EditStepOperations::Pending"),
|
||||||
WorkflowStepEditSuggestions::Resolved {
|
WorkflowStepEditSuggestions::Resolved(ResolvedWorkflowStepEditSuggestions {
|
||||||
title,
|
title,
|
||||||
edit_suggestions,
|
edit_suggestions,
|
||||||
} => f
|
}) => f
|
||||||
.debug_struct("EditStepOperations::Parsed")
|
.debug_struct("EditStepOperations::Parsed")
|
||||||
.field("title", title)
|
.field("title", title)
|
||||||
.field("edit_suggestions", edit_suggestions)
|
.field("edit_suggestions", edit_suggestions)
|
||||||
|
@ -597,7 +609,7 @@ pub struct Context {
|
||||||
_subscriptions: Vec<Subscription>,
|
_subscriptions: Vec<Subscription>,
|
||||||
telemetry: Option<Arc<Telemetry>>,
|
telemetry: Option<Arc<Telemetry>>,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Arc<LanguageRegistry>,
|
||||||
edit_steps: Vec<WorkflowStep>,
|
workflow_steps: Vec<WorkflowStep>,
|
||||||
project: Option<Model<Project>>,
|
project: Option<Model<Project>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +679,7 @@ impl Context {
|
||||||
telemetry,
|
telemetry,
|
||||||
project,
|
project,
|
||||||
language_registry,
|
language_registry,
|
||||||
edit_steps: Vec::new(),
|
workflow_steps: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_message_id = MessageId(clock::Lamport {
|
let first_message_id = MessageId(clock::Lamport {
|
||||||
|
@ -987,8 +999,14 @@ impl Context {
|
||||||
self.summary.as_ref()
|
self.summary.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edit_steps(&self) -> &[WorkflowStep] {
|
pub fn workflow_steps(&self) -> &[WorkflowStep] {
|
||||||
&self.edit_steps
|
&self.workflow_steps
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn workflow_step_for_range(&self, range: Range<language::Anchor>) -> Option<&WorkflowStep> {
|
||||||
|
self.workflow_steps
|
||||||
|
.iter()
|
||||||
|
.find(|step| step.tagged_range == range)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pending_slash_commands(&self) -> &[PendingSlashCommand] {
|
pub fn pending_slash_commands(&self) -> &[PendingSlashCommand] {
|
||||||
|
@ -1133,12 +1151,12 @@ impl Context {
|
||||||
|
|
||||||
fn prune_invalid_edit_steps(&mut self, cx: &mut ModelContext<Self>) {
|
fn prune_invalid_edit_steps(&mut self, cx: &mut ModelContext<Self>) {
|
||||||
let buffer = self.buffer.read(cx);
|
let buffer = self.buffer.read(cx);
|
||||||
let prev_len = self.edit_steps.len();
|
let prev_len = self.workflow_steps.len();
|
||||||
self.edit_steps.retain(|step| {
|
self.workflow_steps.retain(|step| {
|
||||||
step.tagged_range.start.is_valid(buffer) && step.tagged_range.end.is_valid(buffer)
|
step.tagged_range.start.is_valid(buffer) && step.tagged_range.end.is_valid(buffer)
|
||||||
});
|
});
|
||||||
if self.edit_steps.len() != prev_len {
|
if self.workflow_steps.len() != prev_len {
|
||||||
cx.emit(ContextEvent::EditStepsChanged);
|
cx.emit(ContextEvent::WorkflowStepsChanged);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1174,7 +1192,7 @@ impl Context {
|
||||||
|
|
||||||
// Check if a step with the same range already exists
|
// Check if a step with the same range already exists
|
||||||
let existing_step_index = self
|
let existing_step_index = self
|
||||||
.edit_steps
|
.workflow_steps
|
||||||
.binary_search_by(|probe| probe.tagged_range.cmp(&tagged_range, &buffer));
|
.binary_search_by(|probe| probe.tagged_range.cmp(&tagged_range, &buffer));
|
||||||
|
|
||||||
if let Err(ix) = existing_step_index {
|
if let Err(ix) = existing_step_index {
|
||||||
|
@ -1202,10 +1220,10 @@ impl Context {
|
||||||
|
|
||||||
// Insert new steps and generate their corresponding tasks
|
// Insert new steps and generate their corresponding tasks
|
||||||
for (index, step) in new_edit_steps.into_iter().rev() {
|
for (index, step) in new_edit_steps.into_iter().rev() {
|
||||||
self.edit_steps.insert(index, step);
|
self.workflow_steps.insert(index, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.emit(ContextEvent::EditStepsChanged);
|
cx.emit(ContextEvent::WorkflowStepsChanged);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1321,17 +1339,19 @@ impl Context {
|
||||||
|
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
let step_index = this
|
let step_index = this
|
||||||
.edit_steps
|
.workflow_steps
|
||||||
.binary_search_by(|step| {
|
.binary_search_by(|step| {
|
||||||
step.tagged_range.cmp(&tagged_range, this.buffer.read(cx))
|
step.tagged_range.cmp(&tagged_range, this.buffer.read(cx))
|
||||||
})
|
})
|
||||||
.map_err(|_| anyhow!("edit step not found"))?;
|
.map_err(|_| anyhow!("edit step not found"))?;
|
||||||
if let Some(edit_step) = this.edit_steps.get_mut(step_index) {
|
if let Some(edit_step) = this.workflow_steps.get_mut(step_index) {
|
||||||
edit_step.edit_suggestions = WorkflowStepEditSuggestions::Resolved {
|
edit_step.edit_suggestions = WorkflowStepEditSuggestions::Resolved(
|
||||||
|
ResolvedWorkflowStepEditSuggestions {
|
||||||
title: step_suggestions.step_title,
|
title: step_suggestions.step_title,
|
||||||
edit_suggestions: suggestion_groups_by_buffer,
|
edit_suggestions: suggestion_groups_by_buffer,
|
||||||
};
|
},
|
||||||
cx.emit(ContextEvent::EditStepsChanged);
|
);
|
||||||
|
cx.emit(ContextEvent::WorkflowStepsChanged);
|
||||||
}
|
}
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
})?
|
})?
|
||||||
|
@ -2959,7 +2979,7 @@ mod tests {
|
||||||
// Verify that the edit steps were parsed correctly
|
// Verify that the edit steps were parsed correctly
|
||||||
context.read_with(cx, |context, cx| {
|
context.read_with(cx, |context, cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
edit_steps(context, cx),
|
workflow_steps(context, cx),
|
||||||
vec![
|
vec![
|
||||||
(
|
(
|
||||||
Point::new(response_start_row + 2, 0)
|
Point::new(response_start_row + 2, 0)
|
||||||
|
@ -2998,7 +3018,7 @@ mod tests {
|
||||||
// Verify that the last edit step is not pending anymore.
|
// Verify that the last edit step is not pending anymore.
|
||||||
context.read_with(cx, |context, cx| {
|
context.read_with(cx, |context, cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
edit_steps(context, cx),
|
workflow_steps(context, cx),
|
||||||
vec![
|
vec![
|
||||||
(
|
(
|
||||||
Point::new(response_start_row + 2, 0)
|
Point::new(response_start_row + 2, 0)
|
||||||
|
@ -3020,12 +3040,12 @@ mod tests {
|
||||||
Resolved,
|
Resolved,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_steps(
|
fn workflow_steps(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> Vec<(Range<Point>, WorkflowStepEditSuggestionStatus)> {
|
) -> Vec<(Range<Point>, WorkflowStepEditSuggestionStatus)> {
|
||||||
context
|
context
|
||||||
.edit_steps
|
.workflow_steps
|
||||||
.iter()
|
.iter()
|
||||||
.map(|step| {
|
.map(|step| {
|
||||||
let buffer = context.buffer.read(cx);
|
let buffer = context.buffer.read(cx);
|
||||||
|
|
|
@ -604,7 +604,7 @@ impl InlineAssistant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_assist(&mut self, assist_id: InlineAssistId, undo: bool, cx: &mut WindowContext) {
|
pub fn finish_assist(&mut self, assist_id: InlineAssistId, undo: bool, cx: &mut WindowContext) {
|
||||||
if let Some(assist) = self.assists.get(&assist_id) {
|
if let Some(assist) = self.assists.get(&assist_id) {
|
||||||
let assist_group_id = assist.group_id;
|
let assist_group_id = assist.group_id;
|
||||||
if self.assist_groups[&assist_group_id].linked {
|
if self.assist_groups[&assist_group_id].linked {
|
||||||
|
@ -715,8 +715,7 @@ impl InlineAssistant {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) {
|
fn focus_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) {
|
||||||
let assist = &self.assists[&assist_id];
|
let Some(assist) = self.assists.get(&assist_id) else {
|
||||||
let Some(editor) = assist.editor.upgrade() else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -729,6 +728,17 @@ impl InlineAssistant {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.scroll_to_assist(assist_id, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_to_assist(&mut self, assist_id: InlineAssistId, cx: &mut WindowContext) {
|
||||||
|
let Some(assist) = self.assists.get(&assist_id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(editor) = assist.editor.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let position = assist.range.start;
|
let position = assist.range.start;
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.change_selections(None, cx, |selections| {
|
editor.change_selections(None, cx, |selections| {
|
||||||
|
@ -844,6 +854,20 @@ impl InlineAssistant {
|
||||||
assist.codegen.update(cx, |codegen, cx| codegen.stop(cx));
|
assist.codegen.update(cx, |codegen, cx| codegen.stop(cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn status_for_assist(
|
||||||
|
&self,
|
||||||
|
assist_id: InlineAssistId,
|
||||||
|
cx: &WindowContext,
|
||||||
|
) -> Option<CodegenStatus> {
|
||||||
|
let assist = self.assists.get(&assist_id)?;
|
||||||
|
match &assist.codegen.read(cx).status {
|
||||||
|
CodegenStatus::Idle => Some(CodegenStatus::Idle),
|
||||||
|
CodegenStatus::Pending => Some(CodegenStatus::Pending),
|
||||||
|
CodegenStatus::Done => Some(CodegenStatus::Done),
|
||||||
|
CodegenStatus::Error(error) => Some(CodegenStatus::Error(anyhow!("{:?}", error))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update_editor_highlights(&self, editor: &View<Editor>, cx: &mut WindowContext) {
|
fn update_editor_highlights(&self, editor: &View<Editor>, cx: &mut WindowContext) {
|
||||||
let mut gutter_pending_ranges = Vec::new();
|
let mut gutter_pending_ranges = Vec::new();
|
||||||
let mut gutter_transformed_ranges = Vec::new();
|
let mut gutter_transformed_ranges = Vec::new();
|
||||||
|
@ -2000,7 +2024,7 @@ pub struct Codegen {
|
||||||
_subscription: gpui::Subscription,
|
_subscription: gpui::Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CodegenStatus {
|
pub enum CodegenStatus {
|
||||||
Idle,
|
Idle,
|
||||||
Pending,
|
Pending,
|
||||||
Done,
|
Done,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue