on master help sign in
wip: Hooks & trigger characters for completion/signature_help.
9a36d2cBlaž Hrastnik
helix-core/src/auto_pairs.rs+19−7
@@ -28,13 +28,11 @@ const CLOSE_BEFORE: &str = ")]}'\":;> \n"; // includes space and newline
28pub fn hook(doc: &Rope, selection: &Selection, ch: char) -> Option<Transaction> {
28pub fn hook(doc: &Rope, selection: &Selection, ch: char) -> Option<Transaction> {
29 for &(open, close) in PAIRS {
29 for &(open, close) in PAIRS {
30 if open == ch {
30 if open == ch {
31− let t = if open == close {
31+ if open == close {
32− return None;
33− // handle_same()
32+ return handle_same(doc, selection, open);
34 } else {
33 } else {
35− handle_open(doc, selection, open, close, CLOSE_BEFORE)
34+ return Some(handle_open(doc, selection, open, close, CLOSE_BEFORE));
36− };
35+ }
37− return Some(t);
38 }
36 }
39
37
40 if close == ch {
38 if close == ch {
@@ -115,7 +113,21 @@ fn handle_close(doc: &Rope, selection: &Selection, _open: char, close: char) ->
115}
113}
116
114
117// handle cases where open and close is the same, or in triples ("""docstring""")
115// handle cases where open and close is the same, or in triples ("""docstring""")
118−fn handle_same() {
116+fn handle_same(doc: &Rope, selection: &Selection, token: char) -> Option<Transaction> {
119 // if not cursor but selection, wrap
117 // if not cursor but selection, wrap
120 // let next = next char
118 // let next = next char
119+
120+ // if next == bracket {
121+ // // if start of syntax node, insert token twice (new pair because node is complete)
122+ // // elseif colsedBracketAt
123+ // // is_triple == allow triple && next 3 is equal
124+ // // cursor jump over
125+ // }
126+ //} else if allow_triple && followed by triple {
127+ //}
128+ //} else if next != word char && prev != bracket && prev != word char {
129+ // // condition checks for cases like I' where you don't want I'' (or I'm)
130+ // insert pair ("")
131+ //}
132+ None
121}
133}
helix-lsp/src/client.rs+6
@@ -85,6 +85,12 @@ impl Client {
85 }
85 }
86 }
86 }
87
87
88+ pub fn capabilities(&self) -> &lsp::ServerCapabilities {
89+ self.capabilities
90+ .as_ref()
91+ .expect("language server not yet initialized!")
92+ }
93+
88 /// Execute a RPC request on the language server.
94 /// Execute a RPC request on the language server.
89 pub async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result>
95 pub async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result>
90 where
96 where
helix-term/src/commands.rs+103−2
@@ -1122,14 +1122,106 @@ pub fn goto_reference(cx: &mut Context) {
1122 goto(cx, res);
1122 goto(cx, res);
1123}
1123}
1124
1124
1125+pub fn signature_help(cx: &mut Context) {
1126+ let doc = cx.doc();
1127+
1128+ let language_server = match doc.language_server() {
1129+ Some(language_server) => language_server,
1130+ None => return,
1131+ };
1132+
1133+ // TODO: blocking here is not ideal
1134+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor());
1135+
1136+ // TODO: handle fails
1137+
1138+ let res = smol::block_on(language_server.text_document_signature_help(doc.identifier(), pos))
1139+ .unwrap_or_default();
1140+
1141+ if let Some(signature_help) = res {
1142+ log::info!("{:?}", signature_help);
1143+ // signatures
1144+ // active_signature
1145+ // active_parameter
1146+ // render as:
1147+
1148+ // signature
1149+ // ----------
1150+ // doc
1151+
1152+ // with active param highlighted
1153+ }
1154+}
1155+
1125// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
1156// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
1126pub mod insert {
1157pub mod insert {
1127 use super::*;
1158 use super::*;
1128 pub type Hook = fn(&Rope, &Selection, char) -> Option<Transaction>;
1159 pub type Hook = fn(&Rope, &Selection, char) -> Option<Transaction>;
1160+ pub type PostHook = fn(&mut Context, char);
1129
1161
1130 use helix_core::auto_pairs;
1162 use helix_core::auto_pairs;
1131 const HOOKS: &[Hook] = &[auto_pairs::hook];
1163 const HOOKS: &[Hook] = &[auto_pairs::hook];
1132
1164
1165+ fn completion(cx: &mut Context, ch: char) {
1166+ // if ch matches completion char, trigger completion
1167+ let doc = cx.doc();
1168+ let language_server = match doc.language_server() {
1169+ Some(language_server) => language_server,
1170+ None => return,
1171+ };
1172+
1173+ let capabilities = language_server.capabilities();
1174+
1175+ if let lsp::ServerCapabilities {
1176+ completion_provider:
1177+ Some(lsp::CompletionOptions {
1178+ trigger_characters: Some(triggers),
1179+ ..
1180+ }),
1181+ ..
1182+ } = capabilities
1183+ {
1184+ // TODO: what if trigger is multiple chars long
1185+ let is_trigger = triggers.iter().any(|trigger| trigger.contains(ch));
1186+
1187+ if is_trigger {
1188+ super::completion(cx);
1189+ }
1190+ }
1191+ }
1192+
1193+ // TODO: the pre-hook handles ( so post hook never gets called
1194+ fn signature_help(cx: &mut Context, ch: char) {
1195+ // if ch matches signature_help char, trigger
1196+ let doc = cx.doc();
1197+ let language_server = match doc.language_server() {
1198+ Some(language_server) => language_server,
1199+ None => return,
1200+ };
1201+
1202+ let capabilities = language_server.capabilities();
1203+
1204+ if let lsp::ServerCapabilities {
1205+ signature_help_provider:
1206+ Some(lsp::SignatureHelpOptions {
1207+ trigger_characters: Some(triggers),
1208+ // TODO: retrigger_characters
1209+ ..
1210+ }),
1211+ ..
1212+ } = capabilities
1213+ {
1214+ // TODO: what if trigger is multiple chars long
1215+ let is_trigger = triggers.iter().any(|trigger| trigger.contains(ch));
1216+
1217+ if is_trigger {
1218+ super::signature_help(cx);
1219+ }
1220+ }
1221+ }
1222+
1223+ const POST_HOOKS: &[PostHook] = &[completion, signature_help];
1224+
1133 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
1225 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
1134 pub fn insert_char(cx: &mut Context, c: char) {
1226 pub fn insert_char(cx: &mut Context, c: char) {
1135 let doc = cx.doc();
1227 let doc = cx.doc();
@@ -1142,10 +1234,17 @@ pub mod insert {
1142 }
1234 }
1143 }
1235 }
1144
1236
1145− let c = Tendril::from_char(c);
1237+ let t = Tendril::from_char(c);
1146− let transaction = Transaction::insert(doc.text(), doc.selection(), c);
1238+ let transaction = Transaction::insert(doc.text(), doc.selection(), t);
1147
1239
1148 doc.apply(&transaction);
1240 doc.apply(&transaction);
1241+
1242+ // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc)
1243+ // this could also generically look at Transaction, but it's a bit annoying to look at
1244+ // Operation instead of Change.
1245+ for hook in POST_HOOKS {
1246+ hook(cx, c);
1247+ }
1149 }
1248 }
1150
1249
1151 pub fn insert_tab(cx: &mut Context) {
1250 pub fn insert_tab(cx: &mut Context) {
@@ -1162,6 +1261,7 @@ pub mod insert {
1162 let doc = cx.doc();
1261 let doc = cx.doc();
1163 let text = doc.text().slice(..);
1262 let text = doc.text().slice(..);
1164 let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1263 let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1264+ // TODO: offset range.head by 1? when calculating?
1165 let indent_level =
1265 let indent_level =
1166 helix_core::indent::suggested_indent_for_pos(doc.syntax(), text, range.head, true);
1266 helix_core::indent::suggested_indent_for_pos(doc.syntax(), text, range.head, true);
1167 let indent = doc.indent_unit().repeat(indent_level);
1267 let indent = doc.indent_unit().repeat(indent_level);
@@ -1514,6 +1614,7 @@ pub fn completion(cx: &mut Context) {
1514 //
1614 //
1515 // or we could simply use doc.undo + apply when changing between options
1615 // or we could simply use doc.undo + apply when changing between options
1516
1616
1617+ // always present here
1517 let item = item.unwrap();
1618 let item = item.unwrap();
1518
1619
1519 use helix_lsp::{lsp, util};
1620 use helix_lsp::{lsp, util};
helix-term/src/keymap.rs+2
@@ -196,7 +196,9 @@ pub fn default() -> Keymaps {
196 key!('[') => commands::expand_selection,
196 key!('[') => commands::expand_selection,
197
197
198 key!('/') => commands::search,
198 key!('/') => commands::search,
199+ // ? for search_reverse
199 key!('n') => commands::search_next,
200 key!('n') => commands::search_next,
201+ // N for search_prev
200 key!('*') => commands::search_selection,
202 key!('*') => commands::search_selection,
201
203
202 key!('u') => commands::undo,
204 key!('u') => commands::undo,