on master help sign in
Hide signature help if it overlays completion menu (#5523)
commit7a69c40524833f93c3df32ba457a1a658472bb4b authorPascal Kuthe <pascal.kuthe@semimod.de> dateThu 30 Mar 2023, 18:22 (4 years ago) parentab819d8
5 files changed+68−24
helix-term/src/commands.rs+12−3 helix-term/src/commands/lsp.rs+16−1 helix-term/src/ui/completion.rs+5−1 helix-term/src/ui/editor.rs+18−8 helix-term/src/ui/popup.rs+17−11
helix-term/src/commands.rs+12−3
@@ -54,8 +54,8 @@ use crate::{
5454 job::Callback,
5555 keymap::ReverseKeymap,
5656 ui::{
57− self, editor::InsertEvent, overlay::overlayed, FilePicker, Picker, Popup, Prompt,
58− PromptEvent,
57+ self, editor::InsertEvent, lsp::SignatureHelp, overlay::overlayed, FilePicker, Picker,
58+ Popup, Prompt, PromptEvent,
5959 },
6060};
6161
@@ -4261,7 +4261,7 @@ pub fn completion(cx: &mut Context) {
42614261 }
42624262 let size = compositor.size();
42634263 let ui = compositor.find::<ui::EditorView>().unwrap();
4264− ui.set_completion(
4264+ let completion_area = ui.set_completion(
42654265 editor,
42664266 savepoint,
42674267 items,
@@ -4270,6 +4270,15 @@ pub fn completion(cx: &mut Context) {
42704270 trigger_offset,
42714271 size,
42724272 );
4273+ let size = compositor.size();
4274+ let signature_help_area = compositor
4275+ .find_id::<Popup<SignatureHelp>>(SignatureHelp::ID)
4276+ .map(|signature_help| signature_help.area(size, editor));
4277+ // Delete the signature help popup if they intersect.
4278+ if matches!((completion_area, signature_help_area),(Some(a), Some(b)) if a.intersects(b))
4279+ {
4280+ compositor.remove(SignatureHelp::ID);
4281+ }
42734282 },
42744283 );
42754284}
helix-term/src/commands/lsp.rs+16−1
@@ -1221,10 +1221,25 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) {
12211221 contents.set_active_param_range(active_param_range());
12221222
12231223 let old_popup = compositor.find_id::<Popup<SignatureHelp>>(SignatureHelp::ID);
1224− let popup = Popup::new(SignatureHelp::ID, contents)
1224+ let mut popup = Popup::new(SignatureHelp::ID, contents)
12251225 .position(old_popup.and_then(|p| p.get_position()))
12261226 .position_bias(Open::Above)
12271227 .ignore_escape_key(true);
1228+
1229+ // Don't create a popup if it intersects the auto-complete menu.
1230+ let size = compositor.size();
1231+ if compositor
1232+ .find::<ui::EditorView>()
1233+ .unwrap()
1234+ .completion
1235+ .as_mut()
1236+ .map(|completion| completion.area(size, editor))
1237+ .filter(|area| area.intersects(popup.area(size, editor)))
1238+ .is_some()
1239+ {
1240+ return;
1241+ }
1242+
12281243 compositor.replace_or_push(SignatureHelp::ID, popup);
12291244 },
12301245 );
helix-term/src/ui/completion.rs+5−1
@@ -414,6 +414,10 @@ impl Completion {
414414
415415 true
416416 }
417+
418+ pub fn area(&mut self, viewport: Rect, editor: &Editor) -> Rect {
419+ self.popup.area(viewport, editor)
420+ }
417421}
418422
419423impl Component for Completion {
@@ -481,7 +485,7 @@ impl Component for Completion {
481485 };
482486
483487 let popup_area = {
484− let (popup_x, popup_y) = self.popup.get_rel_position(area, cx);
488+ let (popup_x, popup_y) = self.popup.get_rel_position(area, cx.editor);
485489 let (popup_width, popup_height) = self.popup.get_size();
486490 Rect::new(popup_x, popup_y, popup_width, popup_height)
487491 };
helix-term/src/ui/editor.rs+18−8
@@ -952,7 +952,7 @@ impl EditorView {
952952 start_offset: usize,
953953 trigger_offset: usize,
954954 size: Rect,
955− ) {
955+ ) -> Option<Rect> {
956956 let mut completion = Completion::new(
957957 editor,
958958 savepoint,
@@ -964,15 +964,17 @@ impl EditorView {
964964
965965 if completion.is_empty() {
966966 // skip if we got no completion results
967− return;
967+ return None;
968968 }
969969
970+ let area = completion.area(size, editor);
970971 editor.last_completion = None;
971972 self.last_insert.1.push(InsertEvent::TriggerCompletion);
972973
973974 // TODO : propagate required size on resize to completion too
974975 completion.required_size((size.width, size.height));
975976 self.completion = Some(completion);
977+ Some(area)
976978 }
977979
978980 pub fn clear_completion(&mut self, editor: &mut Editor) {
@@ -1256,13 +1258,15 @@ impl Component for EditorView {
12561258 // let completion swallow the event if necessary
12571259 let mut consumed = false;
12581260 if let Some(completion) = &mut self.completion {
1259− // use a fake context here
1260− let mut cx = Context {
1261− editor: cx.editor,
1262− jobs: cx.jobs,
1263− scroll: None,
1261+ let res = {
1262+ // use a fake context here
1263+ let mut cx = Context {
1264+ editor: cx.editor,
1265+ jobs: cx.jobs,
1266+ scroll: None,
1267+ };
1268+ completion.handle_event(event, &mut cx)
12641269 };
1265− let res = completion.handle_event(event, &mut cx);
12661270
12671271 if let EventResult::Consumed(callback) = res {
12681272 consumed = true;
@@ -1270,6 +1274,12 @@ impl Component for EditorView {
12701274 if callback.is_some() {
12711275 // assume close_fn
12721276 self.clear_completion(cx.editor);
1277+
1278+ // In case the popup was deleted because of an intersection w/ the auto-complete menu.
1279+ commands::signature_help_impl(
1280+ &mut cx,
1281+ commands::SignatureHelpInvoked::Automatic,
1282+ );
12731283 }
12741284 }
12751285 }
helix-term/src/ui/popup.rs+17−11
@@ -6,7 +6,10 @@ use crate::{
66use tui::buffer::Buffer as Surface;
77
88use helix_core::Position;
9−use helix_view::graphics::{Margin, Rect};
9+use helix_view::{
10+ graphics::{Margin, Rect},
11+ Editor,
12+};
1013
1114// TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return
1215// a width/height hint. maybe Popup(Box<Component>)
@@ -88,10 +91,10 @@ impl<T: Component> Popup<T> {
8891
8992 /// Calculate the position where the popup should be rendered and return the coordinates of the
9093 /// top left corner.
91− pub fn get_rel_position(&mut self, viewport: Rect, cx: &Context) -> (u16, u16) {
94+ pub fn get_rel_position(&mut self, viewport: Rect, editor: &Editor) -> (u16, u16) {
9295 let position = self
9396 .position
94− .get_or_insert_with(|| cx.editor.cursor().0.unwrap_or_default());
97+ .get_or_insert_with(|| editor.cursor().0.unwrap_or_default());
9598
9699 let (width, height) = self.size;
97100
@@ -155,6 +158,16 @@ impl<T: Component> Popup<T> {
155158 pub fn contents_mut(&mut self) -> &mut T {
156159 &mut self.contents
157160 }
161+
162+ pub fn area(&mut self, viewport: Rect, editor: &Editor) -> Rect {
163+ // trigger required_size so we recalculate if the child changed
164+ self.required_size((viewport.width, viewport.height));
165+
166+ let (rel_x, rel_y) = self.get_rel_position(viewport, editor);
167+
168+ // clip to viewport
169+ viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1))
170+ }
158171}
159172
160173impl<T: Component> Component for Popup<T> {
@@ -232,16 +245,9 @@ impl<T: Component> Component for Popup<T> {
232245 }
233246
234247 fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
235− // trigger required_size so we recalculate if the child changed
236− self.required_size((viewport.width, viewport.height));
237−
248+ let area = self.area(viewport, cx.editor);
238249 cx.scroll = Some(self.scroll);
239250
240− let (rel_x, rel_y) = self.get_rel_position(viewport, cx);
241−
242− // clip to viewport
243− let area = viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1));
244−
245251 // clear area
246252 let background = cx.editor.theme.get("ui.popup");
247253 surface.clear_with(area, background);