From 155594c8b8c6cdc7c00a4dc9891f96216819c600 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 23 Mar 2023 16:11:39 +0100 Subject: [PATCH] Successfully fetch completions from Copilot We still need to process them and return them into a more Zed-friendly structure, but we're getting there. --- crates/copilot/Cargo.toml | 9 +++++ crates/copilot/src/copilot.rs | 70 ++++++++++++++++++++++++++++++++++- crates/copilot/src/request.rs | 45 ++++++++++++++++++++++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/crates/copilot/Cargo.toml b/crates/copilot/Cargo.toml index 190a399475..c17e7cac59 100644 --- a/crates/copilot/Cargo.toml +++ b/crates/copilot/Cargo.toml @@ -23,3 +23,12 @@ serde = { workspace = true } serde_derive = { workspace = true } smol = "1.2.5" futures = "0.3" + +[dev-dependencies] +gpui = { path = "../gpui", features = ["test-support"] } +language = { path = "../language", features = ["test-support"] } +settings = { path = "../settings", features = ["test-support"] } +lsp = { path = "../lsp", features = ["test-support"] } +util = { path = "../util", features = ["test-support"] } +client = { path = "../client", features = ["test-support"] } +workspace = { path = "../workspace", features = ["test-support"] } diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 4abdef0ab4..eafc4d2d98 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -4,8 +4,9 @@ use anyhow::{anyhow, Result}; use async_compression::futures::bufread::GzipDecoder; use client::Client; use gpui::{actions, AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task}; -use language::{Buffer, ToPointUtf16}; +use language::{point_to_lsp, Buffer, ToPointUtf16}; use lsp::LanguageServer; +use settings::Settings; use smol::{fs, io::BufReader, stream::StreamExt}; use std::{ env::consts, @@ -53,6 +54,7 @@ enum SignInStatus { SignedOut, } +#[derive(Debug)] pub enum Event { PromptUserDeviceFlow { user_code: String, @@ -198,7 +200,45 @@ impl Copilot { Err(error) => return Task::ready(Err(error)), }; - cx.spawn(|this, cx| async move { anyhow::Ok(()) }) + let buffer = buffer.read(cx).snapshot(); + let position = position.to_point_utf16(&buffer); + let language_name = buffer.language_at(position).map(|language| language.name()); + let language_name = language_name.as_deref(); + + let path; + let relative_path; + if let Some(file) = buffer.file() { + if let Some(file) = file.as_local() { + path = file.abs_path(cx); + } else { + path = file.full_path(cx); + } + relative_path = file.path().to_path_buf(); + } else { + path = PathBuf::from("/untitled"); + relative_path = PathBuf::from("untitled"); + } + + let settings = cx.global::(); + let request = server.request::(request::GetCompletionsParams { + doc: request::GetCompletionsDocument { + source: buffer.text(), + tab_size: settings.tab_size(language_name).into(), + indent_size: 1, + insert_spaces: !settings.hard_tabs(language_name), + uri: lsp::Url::from_file_path(&path).unwrap(), + path: path.to_string_lossy().into(), + relative_path: relative_path.to_string_lossy().into(), + language_id: "csharp".into(), + position: point_to_lsp(position), + version: 0, + }, + }); + cx.spawn(|this, cx| async move { + dbg!(request.await?); + + anyhow::Ok(()) + }) } pub fn status(&self) -> Status { @@ -302,3 +342,29 @@ async fn get_lsp_binary(http: Arc) -> anyhow::Result { } } } + +#[cfg(test)] +mod tests { + use super::*; + use gpui::TestAppContext; + use util::http; + + #[gpui::test] + async fn test_smoke(cx: &mut TestAppContext) { + Settings::test_async(cx); + let http = http::client(); + let copilot = cx.add_model(|cx| Copilot::start(http, cx)); + smol::Timer::after(std::time::Duration::from_secs(5)).await; + copilot + .update(cx, |copilot, cx| copilot.sign_in(cx)) + .await + .unwrap(); + dbg!(copilot.read_with(cx, |copilot, _| copilot.status())); + + let buffer = cx.add_model(|cx| language::Buffer::new(0, "Lorem ipsum dol", cx)); + copilot + .update(cx, |copilot, cx| copilot.completions(&buffer, 15, cx)) + .await + .unwrap(); + } +} diff --git a/crates/copilot/src/request.rs b/crates/copilot/src/request.rs index 1b02227273..3fe04532e1 100644 --- a/crates/copilot/src/request.rs +++ b/crates/copilot/src/request.rs @@ -87,3 +87,48 @@ impl lsp::request::Request for SignOut { type Result = SignOutResult; const METHOD: &'static str = "signOut"; } + +pub enum GetCompletions {} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetCompletionsParams { + pub doc: GetCompletionsDocument, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetCompletionsDocument { + pub source: String, + pub tab_size: u32, + pub indent_size: u32, + pub insert_spaces: bool, + pub uri: lsp::Url, + pub path: String, + pub relative_path: String, + pub language_id: String, + pub position: lsp::Position, + pub version: usize, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetCompletionsResult { + completions: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Completion { + text: String, + position: lsp::Position, + uuid: String, + range: lsp::Range, + display_text: String, +} + +impl lsp::request::Request for GetCompletions { + type Params = GetCompletionsParams; + type Result = GetCompletionsResult; + const METHOD: &'static str = "getCompletions"; +}