on master help sign in
Retrieve completion options on ctrl-x.
56f2193Blaž Hrastnik
helix-lsp/src/client.rs+43
@@ -196,6 +196,12 @@ impl Client {
196 root_uri: None, // set to project root in the future
196 root_uri: None, // set to project root in the future
197 initialization_options: None,
197 initialization_options: None,
198 capabilities: lsp::ClientCapabilities {
198 capabilities: lsp::ClientCapabilities {
199+ // text_document:
200+ // { completion: {
201+ // dynamic_registration: bool
202+ // completion_item: { snippet, documentation_format, ... }
203+ // completion_item_kind: { }
204+ // } }
199 ..Default::default()
205 ..Default::default()
200 },
206 },
201 trace: None,
207 trace: None,
@@ -358,4 +364,41 @@ impl Client {
358 pub async fn text_document_did_save(&self) -> anyhow::Result<()> {
364 pub async fn text_document_did_save(&self) -> anyhow::Result<()> {
359 unimplemented!()
365 unimplemented!()
360 }
366 }
367+
368+ pub async fn completion(&self, doc: &Document) -> anyhow::Result<Vec<lsp::CompletionItem>> {
369+ // TODO: figure out what should happen when you complete with multiple cursors
370+
371+ let params = lsp::CompletionParams {
372+ text_document_position: lsp::TextDocumentPositionParams {
373+ text_document: text_document_identifier(doc),
374+ position: crate::util::pos_to_lsp_pos(
375+ &doc.text().slice(..),
376+ doc.selection().cursor(),
377+ ),
378+ },
379+ // TODO: support these tokens by async receiving and updating the choice list
380+ work_done_progress_params: lsp::WorkDoneProgressParams {
381+ work_done_token: None,
382+ },
383+ partial_result_params: lsp::PartialResultParams {
384+ partial_result_token: None,
385+ },
386+ context: None,
387+ // lsp::CompletionContext { trigger_kind: , trigger_character: Some(), }
388+ };
389+
390+ let response = self.request::<lsp::request::Completion>(params).await?;
391+
392+ let items = match response {
393+ Some(lsp::CompletionResponse::Array(items)) => items,
394+ // TODO: do something with is_incomplete
395+ Some(lsp::CompletionResponse::List(lsp::CompletionList {
396+ is_incomplete: _is_incomplete,
397+ items,
398+ })) => items,
399+ None => Vec::new(),
400+ };
401+
402+ Ok(items)
403+ }
361}
404}
helix-term/src/application.rs+7−1
@@ -69,10 +69,15 @@ impl Application {
69
69
70 fn render(&mut self) {
70 fn render(&mut self) {
71 let executor = &self.executor;
71 let executor = &self.executor;
72+ let language_servers = &self.language_servers;
72 let editor = &mut self.editor;
73 let editor = &mut self.editor;
73 let compositor = &self.compositor;
74 let compositor = &self.compositor;
74
75
75− let mut cx = crate::compositor::Context { editor, executor };
76+ let mut cx = crate::compositor::Context {
77+ editor,
78+ executor,
79+ language_servers,
80+ };
76 let area = self.terminal.size().unwrap();
81 let area = self.terminal.size().unwrap();
77
82
78 compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
83 compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
@@ -113,6 +118,7 @@ impl Application {
113 let mut cx = crate::compositor::Context {
118 let mut cx = crate::compositor::Context {
114 editor: &mut self.editor,
119 editor: &mut self.editor,
115 executor: &self.executor,
120 executor: &self.executor,
121+ language_servers: &self.language_servers,
116 };
122 };
117 // Handle key events
123 // Handle key events
118 let should_redraw = match event {
124 let should_redraw = match event {
helix-term/src/commands.rs+29
@@ -22,6 +22,7 @@ pub struct Context<'a, 'b> {
22 pub count: usize,
22 pub count: usize,
23 pub view: &'a mut View,
23 pub view: &'a mut View,
24 pub executor: &'a smol::Executor<'b>,
24 pub executor: &'a smol::Executor<'b>,
25+ pub language_servers: &'a helix_lsp::Registry,
25
26
26 pub callback: Option<crate::compositor::Callback>,
27 pub callback: Option<crate::compositor::Callback>,
27}
28}
@@ -831,3 +832,31 @@ pub fn save(cx: &mut Context) {
831 // TODO: handle save errors somehow?
832 // TODO: handle save errors somehow?
832 cx.executor.spawn(cx.view.doc.save()).detach();
833 cx.executor.spawn(cx.view.doc.save()).detach();
833}
834}
835+
836+pub fn completion(cx: &mut Context) {
837+ let language_server = cx.language_servers.get("rust", &cx.executor).unwrap();
838+ use log::info;
839+
840+ // TODO: blocking here is not ideal
841+ let res = smol::block_on(language_server.completion(&cx.view.doc)).expect("completion failed!");
842+
843+ let picker = ui::Picker::new(
844+ res,
845+ |item| {
846+ // format_fn
847+ item.label.as_str().into()
848+ },
849+ |editor: &mut Editor, item| {
850+ //
851+ },
852+ );
853+
854+ cx.callback = Some(Box::new(
855+ move |compositor: &mut Compositor, editor: &mut Editor| {
856+ compositor.push(Box::new(picker));
857+ },
858+ ));
859+
860+ // TODO: when iterating over items, show the docs in popup
861+ // language server client needs to be accessible via a registry of some sort
862+}
helix-term/src/compositor.rs+1
@@ -39,6 +39,7 @@ use helix_view::{Editor, View};
39// shared with commands.rs
39// shared with commands.rs
40pub struct Context<'a> {
40pub struct Context<'a> {
41 pub editor: &'a mut Editor,
41 pub editor: &'a mut Editor,
42+ pub language_servers: &'a helix_lsp::Registry,
42 pub executor: &'static smol::Executor<'static>,
43 pub executor: &'static smol::Executor<'static>,
43}
44}
44
45
helix-term/src/keymap.rs+2
@@ -208,6 +208,8 @@ pub fn default() -> Keymaps {
208 code: KeyCode::Tab,
208 code: KeyCode::Tab,
209 modifiers: Modifiers::NONE
209 modifiers: Modifiers::NONE
210 }] => commands::insert::insert_tab,
210 }] => commands::insert::insert_tab,
211+
212+ vec![ctrl!('x')] => commands::completion,
211 ),
213 ),
212 Mode::Goto => hashmap!(
214 Mode::Goto => hashmap!(
213 vec![Key {
215 vec![Key {
helix-term/src/ui/editor.rs+1
@@ -263,6 +263,7 @@ impl Component for EditorView {
263 let mut cx = commands::Context {
263 let mut cx = commands::Context {
264 view,
264 view,
265 executor: cx.executor,
265 executor: cx.executor,
266+ language_servers: cx.language_servers,
266 count: 1,
267 count: 1,
267 callback: None,
268 callback: None,
268 };
269 };
helix-term/src/ui/picker.rs+3−2
@@ -196,12 +196,13 @@ impl<T> Component for Picker<T> {
196
196
197 // -- Render the frame:
197 // -- Render the frame:
198
198
199− // clear area
199+ // clear area
200 let background = cx.editor.theme.get("ui.background");
200 let background = cx.editor.theme.get("ui.background");
201 for y in area.top()..area.bottom() {
201 for y in area.top()..area.bottom() {
202 for x in area.left()..area.right() {
202 for x in area.left()..area.right() {
203 let cell = surface.get_mut(x, y);
203 let cell = surface.get_mut(x, y);
204+ cell.reset();
204− cell.symbol.clear();
205+ // cell.symbol.clear();
205 cell.set_style(background);
206 cell.set_style(background);
206 }
207 }
207 }
208 }