diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 9253e9f978..2cd34a6dff 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -469,24 +469,34 @@ enum ContextMenu { } impl ContextMenu { - fn select_prev(&mut self, cx: &mut ViewContext) { - match self { - ContextMenu::Completions(menu) => menu.select_prev(cx), - ContextMenu::CodeActions(menu) => menu.select_prev(cx), + fn select_prev(&mut self, cx: &mut ViewContext) -> bool { + if self.visible() { + match self { + ContextMenu::Completions(menu) => menu.select_prev(cx), + ContextMenu::CodeActions(menu) => menu.select_prev(cx), + } + true + } else { + false } } - fn select_next(&mut self, cx: &mut ViewContext) { - match self { - ContextMenu::Completions(menu) => menu.select_next(cx), - ContextMenu::CodeActions(menu) => menu.select_next(cx), + fn select_next(&mut self, cx: &mut ViewContext) -> bool { + if self.visible() { + match self { + ContextMenu::Completions(menu) => menu.select_next(cx), + ContextMenu::CodeActions(menu) => menu.select_next(cx), + } + true + } else { + false } } - fn should_render(&self) -> bool { + fn visible(&self) -> bool { match self { - ContextMenu::Completions(menu) => menu.should_render(), - ContextMenu::CodeActions(menu) => menu.should_render(), + ContextMenu::Completions(menu) => menu.visible(), + ContextMenu::CodeActions(menu) => menu.visible(), } } @@ -525,7 +535,7 @@ impl CompletionsMenu { cx.notify(); } - fn should_render(&self) -> bool { + fn visible(&self) -> bool { !self.matches.is_empty() } @@ -660,7 +670,7 @@ impl CodeActionsMenu { } } - fn should_render(&self) -> bool { + fn visible(&self) -> bool { !self.actions.is_empty() } @@ -1081,7 +1091,7 @@ impl Editor { } fn select(&mut self, Select(phase): &Select, cx: &mut ViewContext) { - self.hide_completions(cx); + self.hide_context_menu(cx); match phase { SelectPhase::Begin { @@ -1383,7 +1393,7 @@ impl Editor { } pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { - if self.hide_completions(cx).is_some() { + if self.hide_context_menu(cx).is_some() { return; } @@ -1711,7 +1721,7 @@ impl Editor { { self.show_completions(&ShowCompletions, cx); } else { - self.hide_completions(cx); + self.hide_context_menu(cx); } } } @@ -1907,10 +1917,8 @@ impl Editor { } this.completion_tasks.retain(|(id, _)| *id > menu.id); - if menu.matches.is_empty() { - this.hide_completions(cx); - } else if this.focused { - this.context_menu = Some(ContextMenu::Completions(menu)); + if this.focused { + this.show_context_menu(ContextMenu::Completions(menu), cx); } cx.notify(); @@ -1938,12 +1946,16 @@ impl Editor { let actions = actions.await?; if !actions.is_empty() { this.update(&mut cx, |this, cx| { - this.context_menu = Some(ContextMenu::CodeActions(CodeActionsMenu { - actions: actions.into(), - selected_item: 0, - list: UniformListState::default(), - })); - cx.notify(); + if this.focused { + this.show_context_menu( + ContextMenu::CodeActions(CodeActionsMenu { + actions: actions.into(), + selected_item: 0, + list: UniformListState::default(), + }), + cx, + ); + } }); } Ok::<_, anyhow::Error>(()) @@ -1951,28 +1963,21 @@ impl Editor { .detach_and_log_err(cx); } - fn hide_completions(&mut self, cx: &mut ViewContext) -> Option { - cx.notify(); - self.completion_tasks.clear(); - self.context_menu.take().and_then(|menu| { - if let ContextMenu::Completions(menu) = menu { - Some(menu) - } else { - None - } - }) - } - pub fn confirm_completion( &mut self, completion_ix: Option, cx: &mut ViewContext, ) -> Option>> { - let context_menu = self.hide_completions(cx)?; - let mat = context_menu + let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? { + menu + } else { + return None; + }; + + let mat = completions_menu .matches - .get(completion_ix.unwrap_or(context_menu.selected_item))?; - let completion = context_menu.completions.get(mat.candidate_id)?; + .get(completion_ix.unwrap_or(completions_menu.selected_item))?; + let completion = completions_menu.completions.get(mat.candidate_id)?; let snippet; let text; @@ -2041,10 +2046,10 @@ impl Editor { })) } - pub fn should_render_context_menu(&self) -> bool { + pub fn showing_context_menu(&self) -> bool { self.context_menu .as_ref() - .map_or(false, |menu| menu.should_render()) + .map_or(false, |menu| menu.visible()) } pub fn render_context_menu(&self, cx: &AppContext) -> Option { @@ -2053,6 +2058,20 @@ impl Editor { .map(|menu| menu.render(self.build_settings.clone(), cx)) } + fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext) { + if !matches!(menu, ContextMenu::Completions(_)) { + self.completion_tasks.clear(); + } + self.context_menu = Some(menu); + cx.notify() + } + + fn hide_context_menu(&mut self, cx: &mut ViewContext) -> Option { + cx.notify(); + self.completion_tasks.clear(); + self.context_menu.take() + } + pub fn insert_snippet( &mut self, insertion_ranges: &[Range], @@ -2859,8 +2878,9 @@ impl Editor { pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { if let Some(context_menu) = self.context_menu.as_mut() { - context_menu.select_prev(cx); - return; + if context_menu.select_prev(cx) { + return; + } } if matches!(self.mode, EditorMode::SingleLine) { @@ -2902,8 +2922,9 @@ impl Editor { pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { if let Some(context_menu) = self.context_menu.as_mut() { - context_menu.select_next(cx); - return; + if context_menu.select_next(cx) { + return; + } } if matches!(self.mode, EditorMode::SingleLine) { @@ -4215,7 +4236,7 @@ impl Editor { .block(completion_menu.filter(query.as_deref(), cx.background().clone())); self.show_completions(&ShowCompletions, cx); } else { - self.hide_completions(cx); + self.hide_context_menu(cx); } } @@ -4767,7 +4788,7 @@ impl View for Editor { self.show_local_cursors = false; self.buffer .update(cx, |buffer, cx| buffer.remove_active_selections(cx)); - self.hide_completions(cx); + self.hide_context_menu(cx); cx.emit(Event::Blurred); cx.notify(); } @@ -4780,7 +4801,7 @@ impl View for Editor { EditorMode::Full => "full", }; cx.map.insert("mode".into(), mode.into()); - if self.context_menu.is_some() { + if matches!(self.context_menu.as_ref(), Some(ContextMenu::Completions(_))) { cx.set.insert("completing".into()); } cx diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 8452989153..37b53b0141 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -880,7 +880,7 @@ impl Element for EditorElement { snapshot = view.snapshot(cx); } - if view.should_render_context_menu() { + if view.showing_context_menu() { let newest_selection_head = view .newest_selection::(&snapshot.buffer_snapshot) .head() diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index d50ca484e2..f246b13f5d 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -2468,7 +2468,7 @@ mod tests { // Confirm a completion on the guest. editor_b.next_notification(&cx_b).await; editor_b.update(&mut cx_b, |editor, cx| { - assert!(editor.should_render_context_menu()); + assert!(editor.showing_context_menu()); editor.confirm_completion(Some(0), cx); assert_eq!(editor.text(cx), "fn main() { a.first_method() }"); });