Skip to content

Commit

Permalink
feat: cycle through function signatures/overloads
Browse files Browse the repository at this point in the history
Add two new commands to cycle through the function signatures.
currently by pressing SHIFT+down and SHIFT+up the function signature will
be changed. (most probably the current key bindings are not suitable for
most developer. any suggestion?)

Signed-off-by: Ben Fekih, Hichem <[email protected]>
  • Loading branch information
karthago1 committed Mar 24, 2024
1 parent 47995bf commit 831d9ef
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 14 deletions.
10 changes: 10 additions & 0 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ impl MappableCommand {
extend_to_line_end, "Extend to line end",
extend_to_line_end_newline, "Extend to line end",
signature_help, "Show signature help",
signature_next, "Show next signature",
signature_previous, "Show previous signature",
smart_tab, "Insert tab if all cursors have all whitespace to their left; otherwise, run a separate command.",
insert_tab, "Insert tab char",
insert_newline, "Insert newline char",
Expand Down Expand Up @@ -5998,3 +6000,11 @@ fn jump_to_word(cx: &mut Context, behaviour: Movement) {
}
jump_to_label(cx, words, behaviour)
}

fn signature_next(cx: &mut Context) {
cx.editor.handlers.next_signature_help();
}

fn signature_previous(cx: &mut Context) {
cx.editor.handlers.previous_signature_help();
}
98 changes: 85 additions & 13 deletions helix-term/src/handlers/signature_help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{job, ui};

#[derive(Debug)]
enum State {
Open,
Open { signature_count: usize },
Closed,
Pending { request: CancelTx },
}
Expand All @@ -37,15 +37,49 @@ const TIMEOUT: u64 = 120;
pub(super) struct SignatureHelpHandler {
trigger: Option<SignatureHelpInvoked>,
state: State,
active_signature: Option<usize>,
}

impl SignatureHelpHandler {
pub fn new() -> SignatureHelpHandler {
SignatureHelpHandler {
trigger: None,
state: State::Closed,
active_signature: None,
}
}

fn next_signature(&mut self) {
let State::Open { signature_count } = self.state else {
return;
};

let value = self
.active_signature
.map(|x| if x >= signature_count - 1 { 0 } else { x + 1 })
.unwrap_or_default();

self.active_signature.replace(value);
}

fn previous_signature(&mut self) {
let State::Open { signature_count } = self.state else {
return;
};

let value = self
.active_signature
.map(|x| if x == 0 { signature_count - 1 } else { x - 1 })
.unwrap_or(signature_count - 1);

self.active_signature.replace(value);
}

/// set the state to closed and clear active_signature
fn close(&mut self) {
self.state = State::Closed;
self.active_signature = None;
}
}

impl helix_event::AsyncHook for SignatureHelpHandler {
Expand All @@ -59,7 +93,7 @@ impl helix_event::AsyncHook for SignatureHelpHandler {
match event {
SignatureHelpEvent::Invoked => {
self.trigger = Some(SignatureHelpInvoked::Manual);
self.state = State::Closed;
self.close();
self.finish_debounce();
return None;
}
Expand All @@ -71,19 +105,35 @@ impl helix_event::AsyncHook for SignatureHelpHandler {
}
}
SignatureHelpEvent::Cancel => {
self.state = State::Closed;
self.close();
return None;
}
SignatureHelpEvent::RequestComplete { open } => {
SignatureHelpEvent::RequestComplete {
open,
signature_count,
active_signature,
} => {
// don't cancel rerequest that was already triggered
if let State::Pending { request } = &self.state {
if !request.is_closed() {
return timeout;
}
}
self.state = if open { State::Open } else { State::Closed };
if open {
if self.active_signature.is_none()
|| self.active_signature.unwrap() >= signature_count
{
self.active_signature = active_signature;
}
self.state = State::Open { signature_count };
} else {
self.close();
}

return timeout;
}
SignatureHelpEvent::Next => self.next_signature(),
SignatureHelpEvent::Previous => self.previous_signature(),
}
if self.trigger.is_none() {
self.trigger = Some(SignatureHelpInvoked::Automatic)
Expand All @@ -95,14 +145,19 @@ impl helix_event::AsyncHook for SignatureHelpHandler {
let invocation = self.trigger.take().unwrap();
let (tx, rx) = cancelation();
self.state = State::Pending { request: tx };
job::dispatch_blocking(move |editor, _| request_signature_help(editor, invocation, rx))
let active_signature = self.active_signature;

job::dispatch_blocking(move |editor, _| {
request_signature_help(editor, invocation, rx, active_signature)
})
}
}

pub fn request_signature_help(
editor: &mut Editor,
invoked: SignatureHelpInvoked,
cancel: CancelRx,
signature_index: Option<usize>,
) {
let (view, doc) = current!(editor);

Expand All @@ -128,7 +183,7 @@ pub fn request_signature_help(
match cancelable_future(future, cancel).await {
Some(Ok(res)) => {
job::dispatch(move |editor, compositor| {
show_signature_help(editor, compositor, invoked, res)
show_signature_help(editor, compositor, invoked, res, signature_index)
})
.await
}
Expand All @@ -143,6 +198,7 @@ pub fn show_signature_help(
compositor: &mut Compositor,
invoked: SignatureHelpInvoked,
response: Option<lsp::SignatureHelp>,
signature_index: Option<usize>,
) {
let config = &editor.config();

Expand Down Expand Up @@ -170,24 +226,32 @@ pub fn show_signature_help(
_ => {
send_blocking(
&editor.handlers.signature_hints,
SignatureHelpEvent::RequestComplete { open: false },
SignatureHelpEvent::RequestComplete {
open: false,
signature_count: 0,
active_signature: None,
},
);
compositor.remove(SignatureHelp::ID);
return;
}
};
send_blocking(
&editor.handlers.signature_hints,
SignatureHelpEvent::RequestComplete { open: true },
SignatureHelpEvent::RequestComplete {
open: true,
signature_count: response.signatures.len(),
active_signature: response.active_signature.map(|x| x as usize),
},
);

let doc = doc!(editor);
let language = doc.language_name().unwrap_or("");

let signature = match response
.signatures
.get(response.active_signature.unwrap_or(0) as usize)
{
let signature_index =
signature_index.unwrap_or_else(|| response.active_signature.unwrap_or_default() as usize);

let signature = match response.signatures.get(signature_index) {
Some(s) => s,
None => return,
};
Expand All @@ -197,6 +261,14 @@ pub fn show_signature_help(
Arc::clone(&editor.syn_loader),
);

if response.signatures.len() > 1 {
contents.set_signature_index(format!(
"{}/{}",
signature_index + 1,
response.signatures.len()
));
}

let signature_doc = if config.lsp.display_signature_help_docs {
signature.documentation.as_ref().map(|doc| match doc {
lsp::Documentation::String(s) => s.clone(),
Expand Down
3 changes: 3 additions & 0 deletions helix-term/src/keymap/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,9 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
"pagedown" => page_down,
"home" => goto_line_start,
"end" => goto_line_end_newline,

"S-down" => signature_next,
"S-up" => signature_previous,
});
hashmap!(
Mode::Normal => normal,
Expand Down
13 changes: 13 additions & 0 deletions helix-term/src/ui/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use super::Popup;
pub struct SignatureHelp {
signature: String,
signature_doc: Option<String>,
signature_index: Option<String>,
/// Part of signature text
active_param_range: Option<(usize, usize)>,

Expand All @@ -36,6 +37,7 @@ impl SignatureHelp {
active_param_range: None,
language,
config_loader,
signature_index: None,
}
}

Expand All @@ -50,6 +52,10 @@ impl SignatureHelp {
pub fn visible_popup(compositor: &mut Compositor) -> Option<&mut Popup<Self>> {
compositor.find_id::<Popup<Self>>(Self::ID)
}

pub fn set_signature_index(&mut self, signature_index: String) {
self.signature_index = Some(signature_index);
}
}

impl Component for SignatureHelp {
Expand All @@ -74,6 +80,13 @@ impl Component for SignatureHelp {
active_param_span,
);

if let Some(signature_index) = &self.signature_index {
let sig_index = Markdown::new(signature_index.clone(), self.config_loader.clone());
let sig_index = sig_index.parse(Some(&cx.editor.theme));
let sig_index_para = Paragraph::new(&sig_index);
sig_index_para.render(area.with_height(1).clip_left(1), surface);
}

let (_, sig_text_height) = crate::ui::text::required_size(&sig_text, area.width);
let sig_text_area = area.clip_top(1).with_height(sig_text_height);
let sig_text_area = sig_text_area.inner(&margin).intersection(surface.area);
Expand Down
8 changes: 8 additions & 0 deletions helix-view/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,12 @@ impl Handlers {
};
send_blocking(&self.signature_hints, event)
}

pub fn next_signature_help(&self) {
send_blocking(&self.signature_hints, lsp::SignatureHelpEvent::Next)
}

pub fn previous_signature_help(&self) {
send_blocking(&self.signature_hints, lsp::SignatureHelpEvent::Previous)
}
}
8 changes: 7 additions & 1 deletion helix-view/src/handlers/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ pub enum SignatureHelpEvent {
Trigger,
ReTrigger,
Cancel,
RequestComplete { open: bool },
RequestComplete {
open: bool,
signature_count: usize,
active_signature: Option<usize>,
},
Next,
Previous,
}

#[derive(Debug)]
Expand Down

0 comments on commit 831d9ef

Please sign in to comment.