wip: Hooks & trigger characters for completion/signature_help.

pull/11/head
Blaž Hrastnik 4 years ago
parent 025d63bc30
commit 9a36d2c2a8

@ -28,13 +28,11 @@ const CLOSE_BEFORE: &str = ")]}'\":;> \n"; // includes space and newline
pub fn hook(doc: &Rope, selection: &Selection, ch: char) -> Option<Transaction> { pub fn hook(doc: &Rope, selection: &Selection, ch: char) -> Option<Transaction> {
for &(open, close) in PAIRS { for &(open, close) in PAIRS {
if open == ch { if open == ch {
let t = if open == close { if open == close {
return None; return handle_same(doc, selection, open);
// handle_same()
} else { } else {
handle_open(doc, selection, open, close, CLOSE_BEFORE) return Some(handle_open(doc, selection, open, close, CLOSE_BEFORE));
}; }
return Some(t);
} }
if close == ch { if close == ch {
@ -115,7 +113,21 @@ fn handle_close(doc: &Rope, selection: &Selection, _open: char, close: char) ->
} }
// handle cases where open and close is the same, or in triples ("""docstring""") // handle cases where open and close is the same, or in triples ("""docstring""")
fn handle_same() { fn handle_same(doc: &Rope, selection: &Selection, token: char) -> Option<Transaction> {
// if not cursor but selection, wrap // if not cursor but selection, wrap
// let next = next char // let next = next char
// if next == bracket {
// // if start of syntax node, insert token twice (new pair because node is complete)
// // elseif colsedBracketAt
// // is_triple == allow triple && next 3 is equal
// // cursor jump over
// }
//} else if allow_triple && followed by triple {
//}
//} else if next != word char && prev != bracket && prev != word char {
// // condition checks for cases like I' where you don't want I'' (or I'm)
// insert pair ("")
//}
None
} }

@ -85,6 +85,12 @@ impl Client {
} }
} }
pub fn capabilities(&self) -> &lsp::ServerCapabilities {
self.capabilities
.as_ref()
.expect("language server not yet initialized!")
}
/// Execute a RPC request on the language server. /// Execute a RPC request on the language server.
pub async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result> pub async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result>
where where

@ -1122,14 +1122,106 @@ pub fn goto_reference(cx: &mut Context) {
goto(cx, res); 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. // NOTE: Transactions in this module get appended to history when we switch back to normal mode.
pub mod insert { pub mod insert {
use super::*; use super::*;
pub type Hook = fn(&Rope, &Selection, char) -> Option<Transaction>; pub type Hook = fn(&Rope, &Selection, char) -> Option<Transaction>;
pub type PostHook = fn(&mut Context, char);
use helix_core::auto_pairs; use helix_core::auto_pairs;
const HOOKS: &[Hook] = &[auto_pairs::hook]; 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. // 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) { pub fn insert_char(cx: &mut Context, c: char) {
let doc = cx.doc(); let doc = cx.doc();
@ -1142,10 +1234,17 @@ pub mod insert {
} }
} }
let c = Tendril::from_char(c); let t = Tendril::from_char(c);
let transaction = Transaction::insert(doc.text(), doc.selection(), c); let transaction = Transaction::insert(doc.text(), doc.selection(), t);
doc.apply(&transaction); 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) { pub fn insert_tab(cx: &mut Context) {
@ -1162,6 +1261,7 @@ pub mod insert {
let doc = cx.doc(); let doc = cx.doc();
let text = doc.text().slice(..); let text = doc.text().slice(..);
let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| { let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
// TODO: offset range.head by 1? when calculating?
let indent_level = let indent_level =
helix_core::indent::suggested_indent_for_pos(doc.syntax(), text, range.head, true); helix_core::indent::suggested_indent_for_pos(doc.syntax(), text, range.head, true);
let indent = doc.indent_unit().repeat(indent_level); 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 // or we could simply use doc.undo + apply when changing between options
// always present here
let item = item.unwrap(); let item = item.unwrap();
use helix_lsp::{lsp, util}; use helix_lsp::{lsp, util};

@ -196,7 +196,9 @@ pub fn default() -> Keymaps {
key!('[') => commands::expand_selection, key!('[') => commands::expand_selection,
key!('/') => commands::search, key!('/') => commands::search,
// ? for search_reverse
key!('n') => commands::search_next, key!('n') => commands::search_next,
// N for search_prev
key!('*') => commands::search_selection, key!('*') => commands::search_selection,
key!('u') => commands::undo, key!('u') => commands::undo,

Loading…
Cancel
Save