From 56f2193811fca2fa20284442c2042fa271464445 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Wed, 23 Dec 2020 16:20:49 +0900 Subject: Retrieve completion options on ctrl-x. --- helix-lsp/src/client.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ helix-term/src/application.rs | 8 +++++++- helix-term/src/commands.rs | 29 +++++++++++++++++++++++++++++ helix-term/src/compositor.rs | 1 + helix-term/src/keymap.rs | 2 ++ helix-term/src/ui/editor.rs | 1 + helix-term/src/ui/picker.rs | 5 +++-- 7 files changed, 86 insertions(+), 3 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 160dd93b..c3bcddd2 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -196,6 +196,12 @@ impl Client { root_uri: None, // set to project root in the future initialization_options: None, capabilities: lsp::ClientCapabilities { + // text_document: + // { completion: { + // dynamic_registration: bool + // completion_item: { snippet, documentation_format, ... } + // completion_item_kind: { } + // } } ..Default::default() }, trace: None, @@ -358,4 +364,41 @@ impl Client { pub async fn text_document_did_save(&self) -> anyhow::Result<()> { unimplemented!() } + + pub async fn completion(&self, doc: &Document) -> anyhow::Result> { + // TODO: figure out what should happen when you complete with multiple cursors + + let params = lsp::CompletionParams { + text_document_position: lsp::TextDocumentPositionParams { + text_document: text_document_identifier(doc), + position: crate::util::pos_to_lsp_pos( + &doc.text().slice(..), + doc.selection().cursor(), + ), + }, + // TODO: support these tokens by async receiving and updating the choice list + work_done_progress_params: lsp::WorkDoneProgressParams { + work_done_token: None, + }, + partial_result_params: lsp::PartialResultParams { + partial_result_token: None, + }, + context: None, + // lsp::CompletionContext { trigger_kind: , trigger_character: Some(), } + }; + + let response = self.request::(params).await?; + + let items = match response { + Some(lsp::CompletionResponse::Array(items)) => items, + // TODO: do something with is_incomplete + Some(lsp::CompletionResponse::List(lsp::CompletionList { + is_incomplete: _is_incomplete, + items, + })) => items, + None => Vec::new(), + }; + + Ok(items) + } } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index e15f21c6..138f55c2 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -69,10 +69,15 @@ impl Application { fn render(&mut self) { let executor = &self.executor; + let language_servers = &self.language_servers; let editor = &mut self.editor; let compositor = &self.compositor; - let mut cx = crate::compositor::Context { editor, executor }; + let mut cx = crate::compositor::Context { + editor, + executor, + language_servers, + }; let area = self.terminal.size().unwrap(); compositor.render(area, self.terminal.current_buffer_mut(), &mut cx); @@ -113,6 +118,7 @@ impl Application { let mut cx = crate::compositor::Context { editor: &mut self.editor, executor: &self.executor, + language_servers: &self.language_servers, }; // Handle key events let should_redraw = match event { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b4b64249..eb23041c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -22,6 +22,7 @@ pub struct Context<'a, 'b> { pub count: usize, pub view: &'a mut View, pub executor: &'a smol::Executor<'b>, + pub language_servers: &'a helix_lsp::Registry, pub callback: Option, } @@ -831,3 +832,31 @@ pub fn save(cx: &mut Context) { // TODO: handle save errors somehow? cx.executor.spawn(cx.view.doc.save()).detach(); } + +pub fn completion(cx: &mut Context) { + let language_server = cx.language_servers.get("rust", &cx.executor).unwrap(); + use log::info; + + // TODO: blocking here is not ideal + let res = smol::block_on(language_server.completion(&cx.view.doc)).expect("completion failed!"); + + let picker = ui::Picker::new( + res, + |item| { + // format_fn + item.label.as_str().into() + }, + |editor: &mut Editor, item| { + // + }, + ); + + cx.callback = Some(Box::new( + move |compositor: &mut Compositor, editor: &mut Editor| { + compositor.push(Box::new(picker)); + }, + )); + + // TODO: when iterating over items, show the docs in popup + // language server client needs to be accessible via a registry of some sort +} diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index b1b92a71..c507b174 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -39,6 +39,7 @@ use helix_view::{Editor, View}; // shared with commands.rs pub struct Context<'a> { pub editor: &'a mut Editor, + pub language_servers: &'a helix_lsp::Registry, pub executor: &'static smol::Executor<'static>, } diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index c1677847..132c81d0 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -208,6 +208,8 @@ pub fn default() -> Keymaps { code: KeyCode::Tab, modifiers: Modifiers::NONE }] => commands::insert::insert_tab, + + vec![ctrl!('x')] => commands::completion, ), Mode::Goto => hashmap!( vec![Key { diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 1bab2eef..25221922 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -263,6 +263,7 @@ impl Component for EditorView { let mut cx = commands::Context { view, executor: cx.executor, + language_servers: cx.language_servers, count: 1, callback: None, }; diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index d4e4d46d..a46886ee 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -196,12 +196,13 @@ impl Component for Picker { // -- Render the frame: - // clear area + // clear area let background = cx.editor.theme.get("ui.background"); for y in area.top()..area.bottom() { for x in area.left()..area.right() { let cell = surface.get_mut(x, y); - cell.symbol.clear(); + cell.reset(); + // cell.symbol.clear(); cell.set_style(background); } } -- cgit v1.2.3-70-g09d2