diff --git a/crates/extension/src/extension.rs b/crates/extension/src/extension.rs index 098b7be225..19267e16ac 100644 --- a/crates/extension/src/extension.rs +++ b/crates/extension/src/extension.rs @@ -1,7 +1,7 @@ pub mod extension_builder; mod extension_manifest; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; use anyhow::{anyhow, bail, Context as _, Result}; @@ -11,6 +11,15 @@ use semantic_version::SemanticVersion; pub use crate::extension_manifest::*; +#[async_trait] +pub trait WorktreeDelegate: Send + Sync + 'static { + fn id(&self) -> u64; + fn root_path(&self) -> String; + async fn read_text_file(&self, path: PathBuf) -> Result; + async fn which(&self, binary_name: String) -> Option; + async fn shell_env(&self) -> Vec<(String, String)>; +} + pub trait KeyValueStoreDelegate: Send + Sync + 'static { fn insert(&self, key: String, docs: String) -> Task>; } diff --git a/crates/extension_host/src/extension_lsp_adapter.rs b/crates/extension_host/src/extension_lsp_adapter.rs index b15fa5adc4..8f0d0f82e3 100644 --- a/crates/extension_host/src/extension_lsp_adapter.rs +++ b/crates/extension_host/src/extension_lsp_adapter.rs @@ -5,6 +5,7 @@ use crate::wasm_host::{ use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use collections::HashMap; +use extension::WorktreeDelegate; use futures::{Future, FutureExt}; use gpui::AsyncAppContext; use language::{ @@ -18,6 +19,35 @@ use std::{any::Any, path::PathBuf, pin::Pin, sync::Arc}; use util::{maybe, ResultExt}; use wasmtime_wasi::WasiView as _; +/// An adapter that allows an [`LspAdapterDelegate`] to be used as a [`WorktreeDelegate`]. +pub struct WorktreeDelegateAdapter(pub Arc); + +#[async_trait] +impl WorktreeDelegate for WorktreeDelegateAdapter { + fn id(&self) -> u64 { + self.0.worktree_id().to_proto() + } + + fn root_path(&self) -> String { + self.0.worktree_root_path().to_string_lossy().to_string() + } + + async fn read_text_file(&self, path: PathBuf) -> Result { + self.0.read_text_file(path).await + } + + async fn which(&self, binary_name: String) -> Option { + self.0 + .which(binary_name.as_ref()) + .await + .map(|path| path.to_string_lossy().to_string()) + } + + async fn shell_env(&self) -> Vec<(String, String)> { + self.0.shell_env().await.into_iter().collect() + } +} + pub struct ExtensionLspAdapter { pub(crate) extension: WasmExtension, pub(crate) language_server_id: LanguageServerName, @@ -45,6 +75,7 @@ impl LspAdapter for ExtensionLspAdapter { let this = self.clone(); |extension, store| { async move { + let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _; let resource = store.data_mut().table().push(delegate)?; let command = extension .call_language_server_command( @@ -166,6 +197,7 @@ impl LspAdapter for ExtensionLspAdapter { let this = self.clone(); |extension, store| { async move { + let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _; let resource = store.data_mut().table().push(delegate)?; let options = extension .call_language_server_initialization_options( @@ -204,6 +236,7 @@ impl LspAdapter for ExtensionLspAdapter { let this = self.clone(); |extension, store| { async move { + let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _; let resource = store.data_mut().table().push(delegate)?; let options = extension .call_language_server_workspace_configuration( diff --git a/crates/extension_host/src/wasm_host/wit.rs b/crates/extension_host/src/wasm_host/wit.rs index bec26cb41d..77e28b824f 100644 --- a/crates/extension_host/src/wasm_host/wit.rs +++ b/crates/extension_host/src/wasm_host/wit.rs @@ -3,14 +3,13 @@ mod since_v0_0_4; mod since_v0_0_6; mod since_v0_1_0; mod since_v0_2_0; -use extension::KeyValueStoreDelegate; +use extension::{KeyValueStoreDelegate, WorktreeDelegate}; use lsp::LanguageServerName; use release_channel::ReleaseChannel; use since_v0_2_0 as latest; use super::{wasm_engine, WasmState}; use anyhow::{anyhow, Context, Result}; -use language::LspAdapterDelegate; use semantic_version::SemanticVersion; use std::{ops::RangeInclusive, sync::Arc}; use wasmtime::{ @@ -152,7 +151,7 @@ impl Extension { store: &mut Store, language_server_id: &LanguageServerName, config: &LanguageServerConfig, - resource: Resource>, + resource: Resource>, ) -> Result> { match self { Extension::V020(ext) => { @@ -183,7 +182,7 @@ impl Extension { store: &mut Store, language_server_id: &LanguageServerName, config: &LanguageServerConfig, - resource: Resource>, + resource: Resource>, ) -> Result, String>> { match self { Extension::V020(ext) => { @@ -229,7 +228,7 @@ impl Extension { &self, store: &mut Store, language_server_id: &LanguageServerName, - resource: Resource>, + resource: Resource>, ) -> Result, String>> { match self { Extension::V020(ext) => { @@ -366,7 +365,7 @@ impl Extension { store: &mut Store, command: &SlashCommand, arguments: &[String], - resource: Option>>, + resource: Option>>, ) -> Result> { match self { Extension::V020(ext) => { diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs b/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs index 3493d2a74d..bd1770de38 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs @@ -3,7 +3,8 @@ use crate::wasm_host::wit::since_v0_0_4; use crate::wasm_host::WasmState; use anyhow::Result; use async_trait::async_trait; -use language::{LanguageServerBinaryStatus, LspAdapterDelegate}; +use extension::WorktreeDelegate; +use language::LanguageServerBinaryStatus; use semantic_version::SemanticVersion; use std::sync::{Arc, OnceLock}; use wasmtime::component::{Linker, Resource}; @@ -21,7 +22,7 @@ wasmtime::component::bindgen!({ }, }); -pub type ExtensionWorktree = Arc; +pub type ExtensionWorktree = Arc; pub fn linker() -> &'static Linker { static LINKER: OnceLock> = OnceLock::new(); @@ -62,7 +63,7 @@ impl From for latest::Command { impl HostWorktree for WasmState { async fn read_text_file( &mut self, - delegate: Resource>, + delegate: Resource>, path: String, ) -> wasmtime::Result> { latest::HostWorktree::read_text_file(self, delegate, path).await @@ -70,14 +71,14 @@ impl HostWorktree for WasmState { async fn shell_env( &mut self, - delegate: Resource>, + delegate: Resource>, ) -> wasmtime::Result { latest::HostWorktree::shell_env(self, delegate).await } async fn which( &mut self, - delegate: Resource>, + delegate: Resource>, binary_name: String, ) -> wasmtime::Result> { latest::HostWorktree::which(self, delegate, binary_name).await diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_0_4.rs b/crates/extension_host/src/wasm_host/wit/since_v0_0_4.rs index eb52d64bf0..b88a444f01 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_0_4.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_0_4.rs @@ -2,7 +2,7 @@ use super::latest; use crate::wasm_host::WasmState; use anyhow::Result; use async_trait::async_trait; -use language::LspAdapterDelegate; +use extension::WorktreeDelegate; use semantic_version::SemanticVersion; use std::sync::{Arc, OnceLock}; use wasmtime::component::{Linker, Resource}; @@ -20,7 +20,7 @@ wasmtime::component::bindgen!({ }, }); -pub type ExtensionWorktree = Arc; +pub type ExtensionWorktree = Arc; pub fn linker() -> &'static Linker { static LINKER: OnceLock> = OnceLock::new(); @@ -71,7 +71,7 @@ impl From for latest::Command { impl HostWorktree for WasmState { async fn read_text_file( &mut self, - delegate: Resource>, + delegate: Resource>, path: String, ) -> wasmtime::Result> { latest::HostWorktree::read_text_file(self, delegate, path).await @@ -79,14 +79,14 @@ impl HostWorktree for WasmState { async fn shell_env( &mut self, - delegate: Resource>, + delegate: Resource>, ) -> wasmtime::Result { latest::HostWorktree::shell_env(self, delegate).await } async fn which( &mut self, - delegate: Resource>, + delegate: Resource>, binary_name: String, ) -> wasmtime::Result> { latest::HostWorktree::which(self, delegate, binary_name).await diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_0_6.rs b/crates/extension_host/src/wasm_host/wit/since_v0_0_6.rs index 18c74258e7..68681936a4 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_0_6.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_0_6.rs @@ -2,7 +2,7 @@ use super::{latest, since_v0_1_0}; use crate::wasm_host::WasmState; use anyhow::Result; use async_trait::async_trait; -use language::LspAdapterDelegate; +use extension::WorktreeDelegate; use semantic_version::SemanticVersion; use std::sync::{Arc, OnceLock}; use wasmtime::component::{Linker, Resource}; @@ -26,7 +26,7 @@ mod settings { include!(concat!(env!("OUT_DIR"), "/since_v0.0.6/settings.rs")); } -pub type ExtensionWorktree = Arc; +pub type ExtensionWorktree = Arc; pub fn linker() -> &'static Linker { static LINKER: OnceLock> = OnceLock::new(); @@ -113,23 +113,20 @@ impl From for latest::CodeLabel { #[async_trait] impl HostWorktree for WasmState { - async fn id( - &mut self, - delegate: Resource>, - ) -> wasmtime::Result { + async fn id(&mut self, delegate: Resource>) -> wasmtime::Result { latest::HostWorktree::id(self, delegate).await } async fn root_path( &mut self, - delegate: Resource>, + delegate: Resource>, ) -> wasmtime::Result { latest::HostWorktree::root_path(self, delegate).await } async fn read_text_file( &mut self, - delegate: Resource>, + delegate: Resource>, path: String, ) -> wasmtime::Result> { latest::HostWorktree::read_text_file(self, delegate, path).await @@ -137,14 +134,14 @@ impl HostWorktree for WasmState { async fn shell_env( &mut self, - delegate: Resource>, + delegate: Resource>, ) -> wasmtime::Result { latest::HostWorktree::shell_env(self, delegate).await } async fn which( &mut self, - delegate: Resource>, + delegate: Resource>, binary_name: String, ) -> wasmtime::Result> { latest::HostWorktree::which(self, delegate, binary_name).await diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs index f707133d17..ff48a2fdaa 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs @@ -5,13 +5,11 @@ use anyhow::{anyhow, bail, Context, Result}; use async_compression::futures::bufread::GzipDecoder; use async_tar::Archive; use async_trait::async_trait; -use extension::KeyValueStoreDelegate; +use extension::{KeyValueStoreDelegate, WorktreeDelegate}; use futures::{io::BufReader, FutureExt as _}; use futures::{lock::Mutex, AsyncReadExt}; use language::LanguageName; -use language::{ - language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate, -}; +use language::{language_settings::AllLanguageSettings, LanguageServerBinaryStatus}; use project::project_settings::ProjectSettings; use semantic_version::SemanticVersion; use std::{ @@ -47,7 +45,7 @@ mod settings { include!(concat!(env!("OUT_DIR"), "/since_v0.1.0/settings.rs")); } -pub type ExtensionWorktree = Arc; +pub type ExtensionWorktree = Arc; pub type ExtensionKeyValueStore = Arc; pub type ExtensionHttpResponseStream = Arc>>; @@ -251,52 +249,38 @@ impl HostKeyValueStore for WasmState { #[async_trait] impl HostWorktree for WasmState { - async fn id( - &mut self, - delegate: Resource>, - ) -> wasmtime::Result { - let delegate = self.table.get(&delegate)?; - Ok(delegate.worktree_id().to_proto()) + async fn id(&mut self, delegate: Resource>) -> wasmtime::Result { + latest::HostWorktree::id(self, delegate).await } async fn root_path( &mut self, - delegate: Resource>, + delegate: Resource>, ) -> wasmtime::Result { - let delegate = self.table.get(&delegate)?; - Ok(delegate.worktree_root_path().to_string_lossy().to_string()) + latest::HostWorktree::root_path(self, delegate).await } async fn read_text_file( &mut self, - delegate: Resource>, + delegate: Resource>, path: String, ) -> wasmtime::Result> { - let delegate = self.table.get(&delegate)?; - Ok(delegate - .read_text_file(path.into()) - .await - .map_err(|error| error.to_string())) + latest::HostWorktree::read_text_file(self, delegate, path).await } async fn shell_env( &mut self, - delegate: Resource>, + delegate: Resource>, ) -> wasmtime::Result { - let delegate = self.table.get(&delegate)?; - Ok(delegate.shell_env().await.into_iter().collect()) + latest::HostWorktree::shell_env(self, delegate).await } async fn which( &mut self, - delegate: Resource>, + delegate: Resource>, binary_name: String, ) -> wasmtime::Result> { - let delegate = self.table.get(&delegate)?; - Ok(delegate - .which(binary_name.as_ref()) - .await - .map(|path| path.to_string_lossy().to_string())) + latest::HostWorktree::which(self, delegate, binary_name).await } fn drop(&mut self, _worktree: Resource) -> Result<()> { diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs index 752392f2f2..09df9aa8b6 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs @@ -6,13 +6,10 @@ use async_compression::futures::bufread::GzipDecoder; use async_tar::Archive; use async_trait::async_trait; use context_servers::manager::ContextServerSettings; -use extension::KeyValueStoreDelegate; +use extension::{KeyValueStoreDelegate, WorktreeDelegate}; use futures::{io::BufReader, FutureExt as _}; use futures::{lock::Mutex, AsyncReadExt}; -use language::{ - language_settings::AllLanguageSettings, LanguageName, LanguageServerBinaryStatus, - LspAdapterDelegate, -}; +use language::{language_settings::AllLanguageSettings, LanguageName, LanguageServerBinaryStatus}; use project::project_settings::ProjectSettings; use semantic_version::SemanticVersion; use std::{ @@ -44,7 +41,7 @@ mod settings { include!(concat!(env!("OUT_DIR"), "/since_v0.2.0/settings.rs")); } -pub type ExtensionWorktree = Arc; +pub type ExtensionWorktree = Arc; pub type ExtensionKeyValueStore = Arc; pub type ExtensionHttpResponseStream = Arc>>; @@ -93,25 +90,22 @@ impl HostProject for WasmState { #[async_trait] impl HostWorktree for WasmState { - async fn id( - &mut self, - delegate: Resource>, - ) -> wasmtime::Result { + async fn id(&mut self, delegate: Resource>) -> wasmtime::Result { let delegate = self.table.get(&delegate)?; - Ok(delegate.worktree_id().to_proto()) + Ok(delegate.id()) } async fn root_path( &mut self, - delegate: Resource>, + delegate: Resource>, ) -> wasmtime::Result { let delegate = self.table.get(&delegate)?; - Ok(delegate.worktree_root_path().to_string_lossy().to_string()) + Ok(delegate.root_path()) } async fn read_text_file( &mut self, - delegate: Resource>, + delegate: Resource>, path: String, ) -> wasmtime::Result> { let delegate = self.table.get(&delegate)?; @@ -123,7 +117,7 @@ impl HostWorktree for WasmState { async fn shell_env( &mut self, - delegate: Resource>, + delegate: Resource>, ) -> wasmtime::Result { let delegate = self.table.get(&delegate)?; Ok(delegate.shell_env().await.into_iter().collect()) @@ -131,14 +125,11 @@ impl HostWorktree for WasmState { async fn which( &mut self, - delegate: Resource>, + delegate: Resource>, binary_name: String, ) -> wasmtime::Result> { let delegate = self.table.get(&delegate)?; - Ok(delegate - .which(binary_name.as_ref()) - .await - .map(|path| path.to_string_lossy().to_string())) + Ok(delegate.which(binary_name).await) } fn drop(&mut self, _worktree: Resource) -> Result<()> { diff --git a/crates/extensions_ui/src/extension_slash_command.rs b/crates/extensions_ui/src/extension_slash_command.rs index 28e13163d4..92c6b148c8 100644 --- a/crates/extensions_ui/src/extension_slash_command.rs +++ b/crates/extensions_ui/src/extension_slash_command.rs @@ -5,6 +5,7 @@ use assistant_slash_command::{ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, SlashCommandResult, }; +use extension_host::extension_lsp_adapter::WorktreeDelegateAdapter; use futures::FutureExt as _; use gpui::{Task, WeakView, WindowContext}; use language::{BufferSnapshot, LspAdapterDelegate}; @@ -97,6 +98,8 @@ impl SlashCommand for ExtensionSlashCommand { move |extension, store| { async move { let resource = if let Some(delegate) = delegate { + let delegate = + Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _; Some(store.data_mut().table().push(delegate)?) } else { None