diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index dfc609fe8c7316668cddb90c61278486df3c8573..710d1c695807e1ccd38006fa6bbe25001b1791a1 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1015,15 +1015,17 @@ impl CodeActionsMenu { pub struct CopilotState { excerpt_id: Option, pending_refresh: Task>, + pending_cycling_refresh: Task>, + cycled: bool, completions: Vec, active_completion_index: usize, - cycled: bool, } impl Default for CopilotState { fn default() -> Self { Self { excerpt_id: None, + pending_cycling_refresh: Task::ready(Some(())), pending_refresh: Task::ready(Some(())), completions: Default::default(), active_completion_index: 0, @@ -1071,6 +1073,22 @@ impl CopilotState { } } + fn cycle_completions(&mut self, direction: Direction) { + match direction { + Direction::Prev => { + self.active_completion_index = if self.active_completion_index == 0 { + self.completions.len() - 1 + } else { + self.active_completion_index - 1 + }; + } + Direction::Next => { + self.active_completion_index = + (self.active_completion_index + 1) % self.completions.len(); + } + } + } + fn push_completion(&mut self, new_completion: copilot::Completion) { for completion in &self.completions { if *completion == new_completion { @@ -2029,13 +2047,13 @@ impl Editor { this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); if had_active_copilot_suggestion { - this.refresh_copilot_suggestions(false, cx); + this.refresh_copilot_suggestions(cx); if !this.has_active_copilot_suggestion(cx) { this.trigger_completion_on_input(&text, cx); } } else { this.trigger_completion_on_input(&text, cx); - this.refresh_copilot_suggestions(false, cx); + this.refresh_copilot_suggestions(cx); } }); } @@ -2117,7 +2135,7 @@ impl Editor { .collect(); this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); - this.refresh_copilot_suggestions(false, cx); + this.refresh_copilot_suggestions(cx); }); } @@ -2515,7 +2533,7 @@ impl Editor { }); } - this.refresh_copilot_suggestions(false, cx); + this.refresh_copilot_suggestions(cx); }); let project = self.project.clone()?; @@ -2808,11 +2826,7 @@ impl Editor { None } - fn refresh_copilot_suggestions( - &mut self, - cycling: bool, - cx: &mut ViewContext, - ) -> Option<()> { + fn refresh_copilot_suggestions(&mut self, cx: &mut ViewContext) -> Option<()> { let copilot = Copilot::global(cx)?; if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() { self.clear_copilot_suggestions(cx); @@ -2838,30 +2852,31 @@ impl Editor { let mut completions = Vec::new(); - let completions_iter = if cycling { - copilot - .update(&mut cx, |copilot, cx| { - copilot.completions(&buffer, buffer_position, cx) - }) - .await - } else { - copilot - .update(&mut cx, |copilot, cx| { - copilot.completions_cycling(&buffer, buffer_position, cx) - }) - .await - }; + // let completions_iter = if cycling { + let completions_iter = copilot + .update(&mut cx, |copilot, cx| { + copilot.completions(&buffer, buffer_position, cx) + }) + .await; + // } else { + // copilot + // .update(&mut cx, |copilot, cx| { + // copilot.completions_cycling(&buffer, buffer_position, cx) + // }) + // .await + // }; completions.extend(completions_iter.log_err().into_iter().flatten()); this.upgrade(&cx)?.update(&mut cx, |this, cx| { if !completions.is_empty() { + this.copilot_state.cycled = false; + this.copilot_state.pending_cycling_refresh = Task::ready(None); this.copilot_state.completions.clear(); this.copilot_state.active_completion_index = 0; this.copilot_state.excerpt_id = Some(cursor.excerpt_id); for completion in completions { this.copilot_state.push_completion(completion); } - this.copilot_state.cycled = cycling; this.update_visible_copilot_suggestion(cx); } }); @@ -2872,9 +2887,49 @@ impl Editor { Some(()) } + fn cycle_suggestions( + &mut self, + direction: Direction, + cx: &mut ViewContext, + ) -> Option<()> { + let copilot = Copilot::global(cx)?; + if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() { + return None; + } + + if self.copilot_state.cycled { + self.copilot_state.cycle_completions(direction); + self.update_visible_copilot_suggestion(cx); + } else { + let cursor = self.selections.newest_anchor().head(); + let (buffer, buffer_position) = + self.buffer.read(cx).text_anchor_for_position(cursor, cx)?; + self.copilot_state.pending_cycling_refresh = cx.spawn_weak(|this, mut cx| async move { + let completions = copilot + .update(&mut cx, |copilot, cx| { + copilot.completions_cycling(&buffer, buffer_position, cx) + }) + .await; + + this.upgrade(&cx)?.update(&mut cx, |this, cx| { + this.copilot_state.cycled = true; + for completion in completions.log_err().into_iter().flatten() { + this.copilot_state.push_completion(completion); + } + this.copilot_state.cycle_completions(direction); + this.update_visible_copilot_suggestion(cx); + }); + + Some(()) + }); + } + + Some(()) + } + fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext) { if !self.has_active_copilot_suggestion(cx) { - self.refresh_copilot_suggestions(false, cx); + self.refresh_copilot_suggestions(cx); return; } @@ -2882,14 +2937,11 @@ impl Editor { } fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext) { - if !self.has_active_copilot_suggestion(cx) || !self.copilot_state.cycled { - self.refresh_copilot_suggestions(true, cx); - return; + if self.has_active_copilot_suggestion(cx) { + self.cycle_suggestions(Direction::Next, cx); + } else { + self.refresh_copilot_suggestions(cx); } - - self.copilot_state.active_completion_index = - (self.copilot_state.active_completion_index + 1) % self.copilot_state.completions.len(); - self.update_visible_copilot_suggestion(cx); } fn previous_copilot_suggestion( @@ -2897,18 +2949,11 @@ impl Editor { _: &copilot::PreviousSuggestion, cx: &mut ViewContext, ) { - if !self.has_active_copilot_suggestion(cx) || !self.copilot_state.cycled { - self.refresh_copilot_suggestions(true, cx); - return; + if self.has_active_copilot_suggestion(cx) { + self.cycle_suggestions(Direction::Prev, cx); + } else { + self.refresh_copilot_suggestions(cx); } - - self.copilot_state.active_completion_index = - if self.copilot_state.active_completion_index == 0 { - self.copilot_state.completions.len() - 1 - } else { - self.copilot_state.active_completion_index - 1 - }; - self.update_visible_copilot_suggestion(cx); } fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext) -> bool { @@ -3255,7 +3300,7 @@ impl Editor { this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); this.insert("", cx); - this.refresh_copilot_suggestions(false, cx); + this.refresh_copilot_suggestions(cx); }); } @@ -3271,7 +3316,7 @@ impl Editor { }) }); this.insert("", cx); - this.refresh_copilot_suggestions(false, cx); + this.refresh_copilot_suggestions(cx); }); } @@ -3367,7 +3412,7 @@ impl Editor { self.transact(cx, |this, cx| { this.buffer.update(cx, |b, cx| b.edit(edits, None, cx)); this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); - this.refresh_copilot_suggestions(false, cx); + this.refresh_copilot_suggestions(cx); }); } @@ -4047,7 +4092,7 @@ impl Editor { } self.request_autoscroll(Autoscroll::fit(), cx); self.unmark_text(cx); - self.refresh_copilot_suggestions(false, cx); + self.refresh_copilot_suggestions(cx); cx.emit(Event::Edited); } } @@ -4062,7 +4107,7 @@ impl Editor { } self.request_autoscroll(Autoscroll::fit(), cx); self.unmark_text(cx); - self.refresh_copilot_suggestions(false, cx); + self.refresh_copilot_suggestions(cx); cx.emit(Event::Edited); } } @@ -6524,7 +6569,7 @@ impl Editor { } fn settings_changed(&mut self, cx: &mut ViewContext) { - self.refresh_copilot_suggestions(false, cx); + self.refresh_copilot_suggestions(cx); } pub fn set_searchable(&mut self, searchable: bool) {