From 03bcbdc33d02e3896e5f50c790d0eba39dbf3266 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 31 Jan 2022 19:12:35 +0100 Subject: [PATCH] WIP --- crates/editor/src/editor.rs | 12 ++++ crates/editor/src/multi_buffer.rs | 13 +++++ crates/language/src/buffer.rs | 97 +++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index db0c099c4b..ed900bc9e2 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -117,6 +117,7 @@ action!(Unfold); action!(FoldSelectedRanges); action!(Scroll, Vector2F); action!(Select, SelectPhase); +action!(ShowAutocomplete); pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec>) { path_openers.push(Box::new(items::BufferOpener)); @@ -224,6 +225,7 @@ pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec) { + let position = self + .newest_selection::(&self.buffer.read(cx).read(cx)) + .head(); + self.buffer + .update(cx, |buffer, cx| buffer.completions(position, cx)) + .detach_and_log_err(cx); + } + pub fn clear(&mut self, cx: &mut ViewContext) { self.start_transaction(cx); self.select_all(&SelectAll, cx); diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index a8867f68d5..aa118c55cb 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -5,6 +5,7 @@ use anyhow::Result; use clock::ReplicaId; use collections::{HashMap, HashSet}; use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task}; +pub use language::Completion; use language::{ Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Outline, OutlineItem, Selection, ToOffset as _, ToPoint as _, TransactionId, @@ -847,6 +848,18 @@ impl MultiBuffer { }) } + pub fn completions( + &self, + position: T, + cx: &mut ModelContext, + ) -> Task>> + where + T: ToOffset, + { + let (buffer, text_anchor) = self.text_anchor_for_position(position, cx); + buffer.update(cx, |buffer, cx| buffer.completions(text_anchor, cx)) + } + pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc> { self.buffers .borrow() diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 014f48f462..257d066b08 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -12,6 +12,7 @@ use crate::{ use anyhow::{anyhow, Result}; use clock::ReplicaId; use futures::FutureExt as _; +use fuzzy::StringMatchCandidate; use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, MutableAppContext, Task}; use lazy_static::lazy_static; use lsp::LanguageServer; @@ -114,6 +115,12 @@ pub struct Diagnostic { pub is_disk_based: bool, } +pub struct Completion { + old_range: Range, + new_text: String, + lsp_completion: lsp::CompletionItem, +} + struct LanguageServerState { server: Arc, latest_snapshot: watch::Sender>, @@ -1611,6 +1618,96 @@ impl Buffer { false } } + + pub fn completions( + &self, + position: T, + cx: &mut ModelContext, + ) -> Task>> + where + T: ToOffset, + { + let file = if let Some(file) = self.file.as_ref() { + file + } else { + return Task::ready(Ok(Default::default())); + }; + + if let Some(file) = file.as_local() { + let server = if let Some(lang) = self.language_server.as_ref() { + lang.server.clone() + } else { + return Task::ready(Ok(Default::default())); + }; + let abs_path = file.abs_path(cx); + let position = self.offset_to_point_utf16(position.to_offset(self)); + + cx.spawn(|this, mut cx| async move { + let t0 = Instant::now(); + let completions = server + .request::(lsp::CompletionParams { + text_document_position: lsp::TextDocumentPositionParams::new( + lsp::TextDocumentIdentifier::new( + lsp::Url::from_file_path(abs_path).unwrap(), + ), + position.to_lsp_position(), + ), + context: Default::default(), + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }) + .await?; + dbg!("completions", t0.elapsed()); + // fuzzy::match_strings(candidates, query, smart_case, max_results, cancel_flag, background) + + let mut completions = if let Some(completions) = completions { + match completions { + lsp::CompletionResponse::Array(completions) => completions, + lsp::CompletionResponse::List(list) => list.items, + } + } else { + Default::default() + }; + + this.update(&mut cx, |this, cx| { + this.edit([0..0], "use std::sync::Arc;\n", cx) + }); + + let mut futures = Vec::new(); + for completion in completions { + futures.push(server.request::(completion)); + } + + let completions = futures::future::try_join_all(futures).await?; + dbg!("resolution", t0.elapsed(), completions); + // let candidates = completions + // .iter() + // .enumerate() + // .map(|(id, completion)| { + // let text = completion + // .filter_text + // .clone() + // .unwrap_or_else(|| completion.label.clone()); + // StringMatchCandidate::new(id, text) + // }) + // .collect::>(); + // let matches = fuzzy::match_strings( + // &candidates, + // "Arc", + // false, + // 100, + // &Default::default(), + // cx.background(), + // ) + // .await; + // dbg!(matches); + + Ok(Default::default()) + }) + } else { + Task::ready(Ok(Default::default())) + } + } } #[cfg(any(test, feature = "test-support"))]