Skip to content

Commit 3f49413

Browse files
committed
Hide signature help if it overlays completion menu (helix-editor#5523)
1 parent 73f805f commit 3f49413

File tree

5 files changed

+68
-24
lines changed

5 files changed

+68
-24
lines changed

helix-term/src/commands.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

419423
impl 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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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,20 +1258,28 @@ 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;
12691273

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

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ use crate::{
66
use tui::buffer::Buffer as Surface;
77

88
use 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

160173
impl<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);

0 commit comments

Comments
 (0)