diff --git a/Cargo.lock b/Cargo.lock
index 6e546ca966..91d78e0b7e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -434,10 +434,10 @@ dependencies = [
"anyhow",
"collections",
"derive_more",
- "futures 0.3.28",
"gpui",
"language",
"parking_lot",
+ "workspace",
]
[[package]]
@@ -3823,6 +3823,7 @@ dependencies = [
"wasmtime",
"wasmtime-wasi",
"wit-component",
+ "workspace",
]
[[package]]
diff --git a/assets/icons/triangle_right.svg b/assets/icons/triangle_right.svg
new file mode 100644
index 0000000000..2c78a316f7
--- /dev/null
+++ b/assets/icons/triangle_right.svg
@@ -0,0 +1 @@
+
diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json
index 2d7e693b3c..67e12b0235 100644
--- a/assets/keymaps/default-linux.json
+++ b/assets/keymaps/default-linux.json
@@ -211,7 +211,9 @@
"ctrl-s": "workspace::Save",
"ctrl->": "assistant::QuoteSelection",
"shift-enter": "assistant::Split",
- "ctrl-r": "assistant::CycleMessageRole"
+ "ctrl-r": "assistant::CycleMessageRole",
+ "enter": "assistant::ConfirmCommand",
+ "alt-enter": "editor::Newline"
}
},
{
diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json
index 09464c3d60..94e8998e5a 100644
--- a/assets/keymaps/default-macos.json
+++ b/assets/keymaps/default-macos.json
@@ -227,7 +227,9 @@
"cmd-s": "workspace::Save",
"cmd->": "assistant::QuoteSelection",
"shift-enter": "assistant::Split",
- "ctrl-r": "assistant::CycleMessageRole"
+ "ctrl-r": "assistant::CycleMessageRole",
+ "enter": "assistant::ConfirmCommand",
+ "alt-enter": "editor::Newline"
}
},
{
diff --git a/crates/assistant/src/ambient_context.rs b/crates/assistant/src/ambient_context.rs
deleted file mode 100644
index cbb63b6044..0000000000
--- a/crates/assistant/src/ambient_context.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-mod current_project;
-mod recent_buffers;
-
-pub use current_project::*;
-pub use recent_buffers::*;
-
-#[derive(Default)]
-pub struct AmbientContext {
- pub recent_buffers: RecentBuffersContext,
- pub current_project: CurrentProjectContext,
-}
-
-impl AmbientContext {
- pub fn snapshot(&self) -> AmbientContextSnapshot {
- AmbientContextSnapshot {
- recent_buffers: self.recent_buffers.snapshot.clone(),
- }
- }
-}
-
-#[derive(Clone, Default, Debug)]
-pub struct AmbientContextSnapshot {
- pub recent_buffers: RecentBuffersSnapshot,
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
-pub enum ContextUpdated {
- Updating,
- Disabled,
-}
diff --git a/crates/assistant/src/ambient_context/current_project.rs b/crates/assistant/src/ambient_context/current_project.rs
deleted file mode 100644
index f89a2a8856..0000000000
--- a/crates/assistant/src/ambient_context/current_project.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-use std::fmt::Write;
-use std::path::{Path, PathBuf};
-use std::sync::Arc;
-use std::time::Duration;
-
-use anyhow::{anyhow, Result};
-use fs::Fs;
-use gpui::{AsyncAppContext, ModelContext, Task, WeakModel};
-use project::{Project, ProjectPath};
-use util::ResultExt;
-
-use crate::ambient_context::ContextUpdated;
-use crate::assistant_panel::Conversation;
-use crate::{LanguageModelRequestMessage, Role};
-
-/// Ambient context about the current project.
-pub struct CurrentProjectContext {
- pub enabled: bool,
- pub message: String,
- pub pending_message: Option>,
-}
-
-#[allow(clippy::derivable_impls)]
-impl Default for CurrentProjectContext {
- fn default() -> Self {
- Self {
- enabled: false,
- message: String::new(),
- pending_message: None,
- }
- }
-}
-
-impl CurrentProjectContext {
- /// Returns the [`CurrentProjectContext`] as a message to the language model.
- pub fn to_message(&self) -> Option {
- self.enabled
- .then(|| LanguageModelRequestMessage {
- role: Role::System,
- content: self.message.clone(),
- })
- .filter(|message| !message.content.is_empty())
- }
-
- /// Updates the [`CurrentProjectContext`] for the given [`Project`].
- pub fn update(
- &mut self,
- fs: Arc,
- project: WeakModel,
- cx: &mut ModelContext,
- ) -> ContextUpdated {
- if !self.enabled {
- self.message.clear();
- self.pending_message = None;
- cx.notify();
- return ContextUpdated::Disabled;
- }
-
- self.pending_message = Some(cx.spawn(|conversation, mut cx| async move {
- const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
- cx.background_executor().timer(DEBOUNCE_TIMEOUT).await;
-
- let Some(path_to_cargo_toml) = Self::path_to_cargo_toml(project, &mut cx).log_err()
- else {
- return;
- };
-
- let Some(path_to_cargo_toml) = path_to_cargo_toml
- .ok_or_else(|| anyhow!("no Cargo.toml"))
- .log_err()
- else {
- return;
- };
-
- let message_task = cx
- .background_executor()
- .spawn(async move { Self::build_message(fs, &path_to_cargo_toml).await });
-
- if let Some(message) = message_task.await.log_err() {
- conversation
- .update(&mut cx, |conversation, cx| {
- conversation.ambient_context.current_project.message = message;
- conversation.count_remaining_tokens(cx);
- cx.notify();
- })
- .log_err();
- }
- }));
-
- ContextUpdated::Updating
- }
-
- async fn build_message(fs: Arc, path_to_cargo_toml: &Path) -> Result {
- let buffer = fs.load(path_to_cargo_toml).await?;
- let cargo_toml: cargo_toml::Manifest = toml::from_str(&buffer)?;
-
- let mut message = String::new();
- writeln!(message, "You are in a Rust project.")?;
-
- if let Some(workspace) = cargo_toml.workspace {
- writeln!(
- message,
- "The project is a Cargo workspace with the following members:"
- )?;
- for member in workspace.members {
- writeln!(message, "- {member}")?;
- }
-
- if !workspace.default_members.is_empty() {
- writeln!(message, "The default members are:")?;
- for member in workspace.default_members {
- writeln!(message, "- {member}")?;
- }
- }
-
- if !workspace.dependencies.is_empty() {
- writeln!(
- message,
- "The following workspace dependencies are installed:"
- )?;
- for dependency in workspace.dependencies.keys() {
- writeln!(message, "- {dependency}")?;
- }
- }
- } else if let Some(package) = cargo_toml.package {
- writeln!(
- message,
- "The project name is \"{name}\".",
- name = package.name
- )?;
-
- let description = package
- .description
- .as_ref()
- .and_then(|description| description.get().ok().cloned());
- if let Some(description) = description.as_ref() {
- writeln!(message, "It describes itself as \"{description}\".")?;
- }
-
- if !cargo_toml.dependencies.is_empty() {
- writeln!(message, "The following dependencies are installed:")?;
- for dependency in cargo_toml.dependencies.keys() {
- writeln!(message, "- {dependency}")?;
- }
- }
- }
-
- Ok(message)
- }
-
- fn path_to_cargo_toml(
- project: WeakModel,
- cx: &mut AsyncAppContext,
- ) -> Result