diff --git a/Cargo.lock b/Cargo.lock index 3abb36adc1d6768dbe81d573ea6a27704ae4fe59..3855baec953955dd114f6d8910bf35d560ed3b7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21356,6 +21356,7 @@ dependencies = [ "zed_actions", "zed_env_vars", "zeta", + "zeta2", "zlog", "zlog_settings", ] @@ -21633,6 +21634,19 @@ dependencies = [ "zlog", ] +[[package]] +name = "zeta2" +version = "0.1.0" +dependencies = [ + "client", + "edit_prediction", + "gpui", + "language", + "project", + "util", + "workspace-hack", +] + [[package]] name = "zeta_cli" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 8a67b28b0e4a7b6e146f4c6a4b84c73d229ceb27..c03d45eab01b64518142cdc828e9dbf22ed071d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -199,6 +199,7 @@ members = [ "crates/zed_actions", "crates/zed_env_vars", "crates/zeta", + "crates/zeta2", "crates/zeta_cli", "crates/zlog", "crates/zlog_settings", @@ -431,6 +432,7 @@ zed = { path = "crates/zed" } zed_actions = { path = "crates/zed_actions" } zed_env_vars = { path = "crates/zed_env_vars" } zeta = { path = "crates/zeta" } +zeta2 = { path = "crates/zeta2" } zlog = { path = "crates/zlog" } zlog_settings = { path = "crates/zlog_settings" } diff --git a/crates/edit_prediction_button/src/edit_prediction_button.rs b/crates/edit_prediction_button/src/edit_prediction_button.rs index 8822c05f6c4d1842fd74d45d876f64736eb62fbc..198bd4fe76ba238ef098ae95092f68613ad67538 100644 --- a/crates/edit_prediction_button/src/edit_prediction_button.rs +++ b/crates/edit_prediction_button/src/edit_prediction_button.rs @@ -233,7 +233,7 @@ impl Render for EditPredictionButton { ) } - EditPredictionProvider::Zed => { + EditPredictionProvider::Zed | EditPredictionProvider::Zed2 => { let enabled = self.editor_enabled.unwrap_or(true); let zeta_icon = if enabled { diff --git a/crates/settings/src/settings_content/language.rs b/crates/settings/src/settings_content/language.rs index de8cf378d1e25f7e84047d788816572ffd97d25c..79d2647c46b48f460cf579ab48ce8f7382f80156 100644 --- a/crates/settings/src/settings_content/language.rs +++ b/crates/settings/src/settings_content/language.rs @@ -52,6 +52,18 @@ pub enum EditPredictionProvider { Copilot, Supermaven, Zed, + Zed2, +} + +impl EditPredictionProvider { + pub fn is_zed(&self) -> bool { + match self { + EditPredictionProvider::Zed | EditPredictionProvider::Zed2 => true, + EditPredictionProvider::None + | EditPredictionProvider::Copilot + | EditPredictionProvider::Supermaven => false, + } + } } /// The contents of the edit prediction settings. diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 5b6cb3924610b89406a37230497fee8ffc511e34..3d7bbe8642c64d7cfff9bfb9169c3df17e18d854 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -163,6 +163,7 @@ workspace.workspace = true zed_actions.workspace = true zed_env_vars.workspace = true zeta.workspace = true +zeta2.workspace = true zlog.workspace = true zlog_settings.workspace = true diff --git a/crates/zed/src/zed/edit_prediction_registry.rs b/crates/zed/src/zed/edit_prediction_registry.rs index ae26427fc6547079b163235f5d1c3df26a489795..e22151368b4886099cad296ac7bd8d3d40596a03 100644 --- a/crates/zed/src/zed/edit_prediction_registry.rs +++ b/crates/zed/src/zed/edit_prediction_registry.rs @@ -220,5 +220,10 @@ fn assign_edit_prediction_provider( editor.set_edit_prediction_provider(Some(provider), window, cx); } } + EditPredictionProvider::Zed2 => { + let provider = cx.new(|_| zeta2::Zeta2EditPredictionProvider::new()); + + editor.set_edit_prediction_provider(Some(provider), window, cx); + } } } diff --git a/crates/zeta2/Cargo.toml b/crates/zeta2/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..5c975bd84b4a8b9fc660ea39c7cf4887cbb0b46e --- /dev/null +++ b/crates/zeta2/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "zeta2" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "GPL-3.0-or-later" + +[lints] +workspace = true + +[lib] +path = "src/zeta2.rs" + +[dependencies] +client.workspace = true +edit_prediction.workspace = true +gpui.workspace = true +language.workspace = true +project.workspace = true +workspace-hack.workspace = true +util.workspace = true diff --git a/crates/zeta2/LICENSE-GPL b/crates/zeta2/LICENSE-GPL new file mode 120000 index 0000000000000000000000000000000000000000..89e542f750cd3860a0598eff0dc34b56d7336dc4 --- /dev/null +++ b/crates/zeta2/LICENSE-GPL @@ -0,0 +1 @@ +../../LICENSE-GPL \ No newline at end of file diff --git a/crates/zeta2/src/zeta2.rs b/crates/zeta2/src/zeta2.rs new file mode 100644 index 0000000000000000000000000000000000000000..46de8a1a8ec36d47bb6bcc3cd68ec3492fae98a1 --- /dev/null +++ b/crates/zeta2/src/zeta2.rs @@ -0,0 +1,154 @@ +use std::{ops::Range, sync::Arc}; + +use gpui::{App, Entity, EntityId, Task, prelude::*}; + +use edit_prediction::{DataCollectionState, Direction, EditPrediction, EditPredictionProvider}; +use language::{Anchor, ToPoint}; + +pub struct Zeta2EditPredictionProvider { + current: Option, + pending: Option>, +} + +impl Zeta2EditPredictionProvider { + pub fn new() -> Self { + Self { + current: None, + pending: None, + } + } +} + +#[derive(Clone)] +struct CurrentEditPrediction { + buffer_id: EntityId, + prediction: EditPrediction, +} + +impl EditPredictionProvider for Zeta2EditPredictionProvider { + fn name() -> &'static str { + // TODO [zeta2] + "zed-predict2" + } + + fn display_name() -> &'static str { + "Zed's Edit Predictions 2" + } + + fn show_completions_in_menu() -> bool { + true + } + + fn show_tab_accept_marker() -> bool { + true + } + + fn data_collection_state(&self, _cx: &App) -> DataCollectionState { + // TODO [zeta2] + DataCollectionState::Unsupported + } + + fn toggle_data_collection(&mut self, _cx: &mut App) { + // TODO [zeta2] + } + + fn usage(&self, _cx: &App) -> Option { + // TODO [zeta2] + None + } + + fn is_enabled( + &self, + _buffer: &Entity, + _cursor_position: language::Anchor, + _cx: &App, + ) -> bool { + true + } + + fn is_refreshing(&self) -> bool { + self.pending.is_some() + } + + fn refresh( + &mut self, + _project: Option>, + buffer: Entity, + cursor_position: language::Anchor, + _debounce: bool, + cx: &mut Context, + ) { + // TODO [zeta2] check account + // TODO [zeta2] actually request completion / interpolate + + let snapshot = buffer.read(cx).snapshot(); + let point = cursor_position.to_point(&snapshot); + let end_anchor = snapshot.anchor_before(language::Point::new( + point.row, + snapshot.line_len(point.row), + )); + + let edits: Arc<[(Range, String)]> = + vec![(cursor_position..end_anchor, "👻".to_string())].into(); + let edits_preview_task = buffer.read(cx).preview_edits(edits.clone(), cx); + + // TODO [zeta2] throttle + // TODO [zeta2] keep 2 requests + self.pending = Some(cx.spawn(async move |this, cx| { + let edits_preview = edits_preview_task.await; + + this.update(cx, |this, cx| { + this.current = Some(CurrentEditPrediction { + buffer_id: buffer.entity_id(), + prediction: EditPrediction { + // TODO! [zeta2] request id? + id: None, + edits: edits.to_vec(), + edit_preview: Some(edits_preview), + }, + }); + this.pending.take(); + cx.notify(); + }) + .ok(); + })); + cx.notify(); + } + + fn cycle( + &mut self, + _buffer: Entity, + _cursor_position: language::Anchor, + _direction: Direction, + _cx: &mut Context, + ) { + } + + fn accept(&mut self, _cx: &mut Context) { + // TODO [zeta2] report accept + self.current.take(); + self.pending.take(); + } + + fn discard(&mut self, _cx: &mut Context) { + self.current.take(); + self.pending.take(); + } + + fn suggest( + &mut self, + buffer: &Entity, + _cursor_position: language::Anchor, + _cx: &mut Context, + ) -> Option { + let current_prediction = self.current.take()?; + + if current_prediction.buffer_id != buffer.entity_id() { + return None; + } + + // TODO [zeta2] interpolate + + Some(current_prediction.prediction) + } +}