From 9a36d2c2a8c4c7c3932de59d1ec145faf3301f2d Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Wed, 24 Mar 2021 18:17:00 +0900 Subject: wip: Hooks & trigger characters for completion/signature_help. --- helix-term/src/commands.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++- helix-term/src/keymap.rs | 2 + 2 files changed, 105 insertions(+), 2 deletions(-) (limited to 'helix-term/src') diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 24fb1709..dd7de06e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1122,14 +1122,106 @@ pub fn goto_reference(cx: &mut Context) { goto(cx, res); } +pub fn signature_help(cx: &mut Context) { + let doc = cx.doc(); + + let language_server = match doc.language_server() { + Some(language_server) => language_server, + None => return, + }; + + // TODO: blocking here is not ideal + let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor()); + + // TODO: handle fails + + let res = smol::block_on(language_server.text_document_signature_help(doc.identifier(), pos)) + .unwrap_or_default(); + + if let Some(signature_help) = res { + log::info!("{:?}", signature_help); + // signatures + // active_signature + // active_parameter + // render as: + + // signature + // ---------- + // doc + + // with active param highlighted + } +} + // NOTE: Transactions in this module get appended to history when we switch back to normal mode. pub mod insert { use super::*; pub type Hook = fn(&Rope, &Selection, char) -> Option; + pub type PostHook = fn(&mut Context, char); use helix_core::auto_pairs; const HOOKS: &[Hook] = &[auto_pairs::hook]; + fn completion(cx: &mut Context, ch: char) { + // if ch matches completion char, trigger completion + let doc = cx.doc(); + let language_server = match doc.language_server() { + Some(language_server) => language_server, + None => return, + }; + + let capabilities = language_server.capabilities(); + + if let lsp::ServerCapabilities { + completion_provider: + Some(lsp::CompletionOptions { + trigger_characters: Some(triggers), + .. + }), + .. + } = capabilities + { + // TODO: what if trigger is multiple chars long + let is_trigger = triggers.iter().any(|trigger| trigger.contains(ch)); + + if is_trigger { + super::completion(cx); + } + } + } + + // TODO: the pre-hook handles ( so post hook never gets called + fn signature_help(cx: &mut Context, ch: char) { + // if ch matches signature_help char, trigger + let doc = cx.doc(); + let language_server = match doc.language_server() { + Some(language_server) => language_server, + None => return, + }; + + let capabilities = language_server.capabilities(); + + if let lsp::ServerCapabilities { + signature_help_provider: + Some(lsp::SignatureHelpOptions { + trigger_characters: Some(triggers), + // TODO: retrigger_characters + .. + }), + .. + } = capabilities + { + // TODO: what if trigger is multiple chars long + let is_trigger = triggers.iter().any(|trigger| trigger.contains(ch)); + + if is_trigger { + super::signature_help(cx); + } + } + } + + const POST_HOOKS: &[PostHook] = &[completion, signature_help]; + // TODO: insert means add text just before cursor, on exit we should be on the last letter. pub fn insert_char(cx: &mut Context, c: char) { let doc = cx.doc(); @@ -1142,10 +1234,17 @@ pub mod insert { } } - let c = Tendril::from_char(c); - let transaction = Transaction::insert(doc.text(), doc.selection(), c); + let t = Tendril::from_char(c); + let transaction = Transaction::insert(doc.text(), doc.selection(), t); doc.apply(&transaction); + + // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc) + // this could also generically look at Transaction, but it's a bit annoying to look at + // Operation instead of Change. + for hook in POST_HOOKS { + hook(cx, c); + } } pub fn insert_tab(cx: &mut Context) { @@ -1162,6 +1261,7 @@ pub mod insert { let doc = cx.doc(); let text = doc.text().slice(..); let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| { + // TODO: offset range.head by 1? when calculating? let indent_level = helix_core::indent::suggested_indent_for_pos(doc.syntax(), text, range.head, true); let indent = doc.indent_unit().repeat(indent_level); @@ -1514,6 +1614,7 @@ pub fn completion(cx: &mut Context) { // // or we could simply use doc.undo + apply when changing between options + // always present here let item = item.unwrap(); use helix_lsp::{lsp, util}; diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 824d469d..aa1f8cce 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -196,7 +196,9 @@ pub fn default() -> Keymaps { key!('[') => commands::expand_selection, key!('/') => commands::search, + // ? for search_reverse key!('n') => commands::search_next, + // N for search_prev key!('*') => commands::search_selection, key!('u') => commands::undo, -- cgit v1.2.3-70-g09d2