aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/ui/popup.rs
diff options
context:
space:
mode:
authorGokul Soumya2022-07-19 02:28:24 +0000
committerGitHub2022-07-19 02:28:24 +0000
commit791bf7e50a19bcf7612788deb7514847089cb976 (patch)
tree0bac607be8b940aed8000b77a2f4dfa2e14882b8 /helix-term/src/ui/popup.rs
parent02f009921007301284cbb0db4bc36bc629088fbb (diff)
Add lsp signature help (#1755)
* Add lsp signature help * Do not move signature help popup on multiple triggers * Highlight current parameter in signature help * Auto close signature help * Position signature help above to not block completion * Update signature help on backspace/insert mode delete * Add lsp.auto-signature-help config option * Add serde default annotation for LspConfig * Show LSP inactive message only if signature help is invoked manually * Do not assume valid signature help response from LSP Malformed LSP responses are common, and these should not crash the editor. * Check signature help capability before sending request * Reuse Open enum for PositionBias in popup * Close signature popup and exit insert mode on escape * Add config to control signature help docs display * Use new Margin api in signature help * Invoke signature help on changing to insert mode
Diffstat (limited to 'helix-term/src/ui/popup.rs')
-rw-r--r--helix-term/src/ui/popup.rs59
1 files changed, 50 insertions, 9 deletions
diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs
index f5b79526..77ab2462 100644
--- a/helix-term/src/ui/popup.rs
+++ b/helix-term/src/ui/popup.rs
@@ -1,4 +1,5 @@
use crate::{
+ commands::Open,
compositor::{Callback, Component, Context, EventResult},
ctrl, key,
};
@@ -17,8 +18,10 @@ pub struct Popup<T: Component> {
margin: Margin,
size: (u16, u16),
child_size: (u16, u16),
+ position_bias: Open,
scroll: usize,
auto_close: bool,
+ ignore_escape_key: bool,
id: &'static str,
}
@@ -29,15 +32,27 @@ impl<T: Component> Popup<T> {
position: None,
margin: Margin::none(),
size: (0, 0),
+ position_bias: Open::Below,
child_size: (0, 0),
scroll: 0,
auto_close: false,
+ ignore_escape_key: false,
id,
}
}
- pub fn set_position(&mut self, pos: Option<Position>) {
+ pub fn position(mut self, pos: Option<Position>) -> Self {
self.position = pos;
+ self
+ }
+
+ pub fn get_position(&self) -> Option<Position> {
+ self.position
+ }
+
+ pub fn position_bias(mut self, bias: Open) -> Self {
+ self.position_bias = bias;
+ self
}
pub fn margin(mut self, margin: Margin) -> Self {
@@ -50,6 +65,18 @@ impl<T: Component> Popup<T> {
self
}
+ /// Ignores an escape keypress event, letting the outer layer
+ /// (usually the editor) handle it. This is useful for popups
+ /// in insert mode like completion and signature help where
+ /// the popup is closed on the mode change from insert to normal
+ /// which is done with the escape key. Otherwise the popup consumes
+ /// the escape key event and closes it, and an additional escape
+ /// would be required to exit insert mode.
+ pub fn ignore_escape_key(mut self, ignore: bool) -> Self {
+ self.ignore_escape_key = ignore;
+ self
+ }
+
pub fn get_rel_position(&mut self, viewport: Rect, cx: &Context) -> (u16, u16) {
let position = self
.position
@@ -68,13 +95,23 @@ impl<T: Component> Popup<T> {
rel_x = rel_x.saturating_sub((rel_x + width).saturating_sub(viewport.width));
}
- // TODO: be able to specify orientation preference. We want above for most popups, below
- // for menus/autocomplete.
- if viewport.height > rel_y + height {
- rel_y += 1 // position below point
- } else {
- rel_y = rel_y.saturating_sub(height) // position above point
- }
+ let can_put_below = viewport.height > rel_y + height;
+ let can_put_above = rel_y.checked_sub(height).is_some();
+ let final_pos = match self.position_bias {
+ Open::Below => match can_put_below {
+ true => Open::Below,
+ false => Open::Above,
+ },
+ Open::Above => match can_put_above {
+ true => Open::Above,
+ false => Open::Below,
+ },
+ };
+
+ rel_y = match final_pos {
+ Open::Above => rel_y.saturating_sub(height),
+ Open::Below => rel_y + 1,
+ };
(rel_x, rel_y)
}
@@ -112,9 +149,13 @@ impl<T: Component> Component for Popup<T> {
_ => return EventResult::Ignored(None),
};
+ if key!(Esc) == key.into() && self.ignore_escape_key {
+ return EventResult::Ignored(None);
+ }
+
let close_fn: Callback = Box::new(|compositor, _| {
// remove the layer
- compositor.pop();
+ compositor.remove(self.id.as_ref());
});
match key.into() {