Use Extension
trait in ExtensionLspAdapter
(#20704)
This PR updates the `ExtensionLspAdapter` to go through the `Extension` trait for interacting with extensions rather than going through the `WasmHost` directly. Release Notes: - N/A
This commit is contained in:
parent
332b33716a
commit
1855a312d0
10 changed files with 662 additions and 272 deletions
|
@ -1,17 +1,20 @@
|
||||||
pub mod extension_builder;
|
pub mod extension_builder;
|
||||||
mod extension_manifest;
|
mod extension_manifest;
|
||||||
mod slash_command;
|
mod types;
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ::lsp::LanguageServerName;
|
||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use fs::normalize_path;
|
||||||
use gpui::Task;
|
use gpui::Task;
|
||||||
|
use language::LanguageName;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
|
|
||||||
pub use crate::extension_manifest::*;
|
pub use crate::extension_manifest::*;
|
||||||
pub use crate::slash_command::*;
|
pub use crate::types::*;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait WorktreeDelegate: Send + Sync + 'static {
|
pub trait WorktreeDelegate: Send + Sync + 'static {
|
||||||
|
@ -34,6 +37,43 @@ pub trait Extension: Send + Sync + 'static {
|
||||||
/// Returns the path to this extension's working directory.
|
/// Returns the path to this extension's working directory.
|
||||||
fn work_dir(&self) -> Arc<Path>;
|
fn work_dir(&self) -> Arc<Path>;
|
||||||
|
|
||||||
|
/// Returns a path relative to this extension's working directory.
|
||||||
|
fn path_from_extension(&self, path: &Path) -> PathBuf {
|
||||||
|
normalize_path(&self.work_dir().join(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn language_server_command(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
language_name: LanguageName,
|
||||||
|
worktree: Arc<dyn WorktreeDelegate>,
|
||||||
|
) -> Result<Command>;
|
||||||
|
|
||||||
|
async fn language_server_initialization_options(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
language_name: LanguageName,
|
||||||
|
worktree: Arc<dyn WorktreeDelegate>,
|
||||||
|
) -> Result<Option<String>>;
|
||||||
|
|
||||||
|
async fn language_server_workspace_configuration(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
worktree: Arc<dyn WorktreeDelegate>,
|
||||||
|
) -> Result<Option<String>>;
|
||||||
|
|
||||||
|
async fn labels_for_completions(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
completions: Vec<Completion>,
|
||||||
|
) -> Result<Vec<Option<CodeLabel>>>;
|
||||||
|
|
||||||
|
async fn labels_for_symbols(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
symbols: Vec<Symbol>,
|
||||||
|
) -> Result<Vec<Option<CodeLabel>>>;
|
||||||
|
|
||||||
async fn complete_slash_command_argument(
|
async fn complete_slash_command_argument(
|
||||||
&self,
|
&self,
|
||||||
command: SlashCommand,
|
command: SlashCommand,
|
||||||
|
@ -44,7 +84,7 @@ pub trait Extension: Send + Sync + 'static {
|
||||||
&self,
|
&self,
|
||||||
command: SlashCommand,
|
command: SlashCommand,
|
||||||
arguments: Vec<String>,
|
arguments: Vec<String>,
|
||||||
resource: Option<Arc<dyn WorktreeDelegate>>,
|
worktree: Option<Arc<dyn WorktreeDelegate>>,
|
||||||
) -> Result<SlashCommandOutput>;
|
) -> Result<SlashCommandOutput>;
|
||||||
|
|
||||||
async fn suggest_docs_packages(&self, provider: Arc<str>) -> Result<Vec<String>>;
|
async fn suggest_docs_packages(&self, provider: Arc<str>) -> Result<Vec<String>>;
|
||||||
|
|
49
crates/extension/src/types.rs
Normal file
49
crates/extension/src/types.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
mod lsp;
|
||||||
|
mod slash_command;
|
||||||
|
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
pub use lsp::*;
|
||||||
|
pub use slash_command::*;
|
||||||
|
|
||||||
|
/// A list of environment variables.
|
||||||
|
pub type EnvVars = Vec<(String, String)>;
|
||||||
|
|
||||||
|
/// A command.
|
||||||
|
pub struct Command {
|
||||||
|
/// The command to execute.
|
||||||
|
pub command: String,
|
||||||
|
/// The arguments to pass to the command.
|
||||||
|
pub args: Vec<String>,
|
||||||
|
/// The environment variables to set for the command.
|
||||||
|
pub env: EnvVars,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A label containing some code.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CodeLabel {
|
||||||
|
/// The source code to parse with Tree-sitter.
|
||||||
|
pub code: String,
|
||||||
|
/// The spans to display in the label.
|
||||||
|
pub spans: Vec<CodeLabelSpan>,
|
||||||
|
/// The range of the displayed label to include when filtering.
|
||||||
|
pub filter_range: Range<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A span within a code label.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum CodeLabelSpan {
|
||||||
|
/// A range into the parsed code.
|
||||||
|
CodeRange(Range<usize>),
|
||||||
|
/// A span containing a code literal.
|
||||||
|
Literal(CodeLabelSpanLiteral),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A span containing a code literal.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CodeLabelSpanLiteral {
|
||||||
|
/// The literal text.
|
||||||
|
pub text: String,
|
||||||
|
/// The name of the highlight to use for this literal.
|
||||||
|
pub highlight_name: Option<String>,
|
||||||
|
}
|
96
crates/extension/src/types/lsp.rs
Normal file
96
crates/extension/src/types/lsp.rs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
use std::option::Option;
|
||||||
|
|
||||||
|
/// An LSP completion.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Completion {
|
||||||
|
pub label: String,
|
||||||
|
pub label_details: Option<CompletionLabelDetails>,
|
||||||
|
pub detail: Option<String>,
|
||||||
|
pub kind: Option<CompletionKind>,
|
||||||
|
pub insert_text_format: Option<InsertTextFormat>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of an LSP completion.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum CompletionKind {
|
||||||
|
Text,
|
||||||
|
Method,
|
||||||
|
Function,
|
||||||
|
Constructor,
|
||||||
|
Field,
|
||||||
|
Variable,
|
||||||
|
Class,
|
||||||
|
Interface,
|
||||||
|
Module,
|
||||||
|
Property,
|
||||||
|
Unit,
|
||||||
|
Value,
|
||||||
|
Enum,
|
||||||
|
Keyword,
|
||||||
|
Snippet,
|
||||||
|
Color,
|
||||||
|
File,
|
||||||
|
Reference,
|
||||||
|
Folder,
|
||||||
|
EnumMember,
|
||||||
|
Constant,
|
||||||
|
Struct,
|
||||||
|
Event,
|
||||||
|
Operator,
|
||||||
|
TypeParameter,
|
||||||
|
Other(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Label details for an LSP completion.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CompletionLabelDetails {
|
||||||
|
pub detail: Option<String>,
|
||||||
|
pub description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines how to interpret the insert text in a completion item.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum InsertTextFormat {
|
||||||
|
PlainText,
|
||||||
|
Snippet,
|
||||||
|
Other(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An LSP symbol.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Symbol {
|
||||||
|
pub kind: SymbolKind,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of an LSP symbol.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum SymbolKind {
|
||||||
|
File,
|
||||||
|
Module,
|
||||||
|
Namespace,
|
||||||
|
Package,
|
||||||
|
Class,
|
||||||
|
Method,
|
||||||
|
Property,
|
||||||
|
Field,
|
||||||
|
Constructor,
|
||||||
|
Enum,
|
||||||
|
Interface,
|
||||||
|
Function,
|
||||||
|
Variable,
|
||||||
|
Constant,
|
||||||
|
String,
|
||||||
|
Number,
|
||||||
|
Boolean,
|
||||||
|
Array,
|
||||||
|
Object,
|
||||||
|
Key,
|
||||||
|
Null,
|
||||||
|
EnumMember,
|
||||||
|
Struct,
|
||||||
|
Event,
|
||||||
|
Operator,
|
||||||
|
TypeParameter,
|
||||||
|
Other(i32),
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ pub mod wasm_host;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod extension_store_test;
|
mod extension_store_test;
|
||||||
|
|
||||||
use crate::{extension_lsp_adapter::ExtensionLspAdapter, wasm_host::wit};
|
use crate::extension_lsp_adapter::ExtensionLspAdapter;
|
||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_tar::Archive;
|
use async_tar::Archive;
|
||||||
|
@ -1238,13 +1238,9 @@ impl ExtensionStore {
|
||||||
this.registration_hooks.register_lsp_adapter(
|
this.registration_hooks.register_lsp_adapter(
|
||||||
language.clone(),
|
language.clone(),
|
||||||
ExtensionLspAdapter {
|
ExtensionLspAdapter {
|
||||||
extension: wasm_extension.clone(),
|
extension: extension.clone(),
|
||||||
host: this.wasm_host.clone(),
|
|
||||||
language_server_id: language_server_id.clone(),
|
language_server_id: language_server_id.clone(),
|
||||||
config: wit::LanguageServerConfig {
|
language_name: language.clone(),
|
||||||
name: language_server_id.0.to_string(),
|
|
||||||
language_name: language.to_string(),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
use crate::wasm_host::{
|
use anyhow::{Context, Result};
|
||||||
wit::{self, LanguageServerConfig},
|
|
||||||
WasmExtension, WasmHost,
|
|
||||||
};
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use extension::WorktreeDelegate;
|
use extension::{Extension, WorktreeDelegate};
|
||||||
use futures::{Future, FutureExt};
|
use futures::{Future, FutureExt};
|
||||||
use gpui::AsyncAppContext;
|
use gpui::AsyncAppContext;
|
||||||
use language::{
|
use language::{
|
||||||
CodeLabel, HighlightId, Language, LanguageToolchainStore, LspAdapter, LspAdapterDelegate,
|
CodeLabel, HighlightId, Language, LanguageName, LanguageToolchainStore, LspAdapter,
|
||||||
|
LspAdapterDelegate,
|
||||||
};
|
};
|
||||||
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName};
|
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -17,7 +14,6 @@ use serde_json::Value;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::{any::Any, path::PathBuf, pin::Pin, sync::Arc};
|
use std::{any::Any, path::PathBuf, pin::Pin, sync::Arc};
|
||||||
use util::{maybe, ResultExt};
|
use util::{maybe, ResultExt};
|
||||||
use wasmtime_wasi::WasiView as _;
|
|
||||||
|
|
||||||
/// An adapter that allows an [`LspAdapterDelegate`] to be used as a [`WorktreeDelegate`].
|
/// An adapter that allows an [`LspAdapterDelegate`] to be used as a [`WorktreeDelegate`].
|
||||||
pub struct WorktreeDelegateAdapter(pub Arc<dyn LspAdapterDelegate>);
|
pub struct WorktreeDelegateAdapter(pub Arc<dyn LspAdapterDelegate>);
|
||||||
|
@ -49,16 +45,15 @@ impl WorktreeDelegate for WorktreeDelegateAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtensionLspAdapter {
|
pub struct ExtensionLspAdapter {
|
||||||
pub(crate) extension: WasmExtension,
|
pub(crate) extension: Arc<dyn Extension>,
|
||||||
pub(crate) language_server_id: LanguageServerName,
|
pub(crate) language_server_id: LanguageServerName,
|
||||||
pub(crate) config: LanguageServerConfig,
|
pub(crate) language_name: LanguageName,
|
||||||
pub(crate) host: Arc<WasmHost>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl LspAdapter for ExtensionLspAdapter {
|
impl LspAdapter for ExtensionLspAdapter {
|
||||||
fn name(&self) -> LanguageServerName {
|
fn name(&self) -> LanguageServerName {
|
||||||
LanguageServerName(self.config.name.clone().into())
|
self.language_server_id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_language_server_command<'a>(
|
fn get_language_server_command<'a>(
|
||||||
|
@ -69,33 +64,17 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
_: &'a mut AsyncAppContext,
|
_: &'a mut AsyncAppContext,
|
||||||
) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
|
) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
|
||||||
async move {
|
async move {
|
||||||
|
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
||||||
let command = self
|
let command = self
|
||||||
.extension
|
.extension
|
||||||
.call({
|
.language_server_command(
|
||||||
let this = self.clone();
|
self.language_server_id.clone(),
|
||||||
|extension, store| {
|
self.language_name.clone(),
|
||||||
async move {
|
delegate,
|
||||||
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
)
|
||||||
let resource = store.data_mut().table().push(delegate)?;
|
|
||||||
let command = extension
|
|
||||||
.call_language_server_command(
|
|
||||||
store,
|
|
||||||
&this.language_server_id,
|
|
||||||
&this.config,
|
|
||||||
resource,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
.map_err(|e| anyhow!("{}", e))?;
|
|
||||||
anyhow::Ok(command)
|
|
||||||
}
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let path = self
|
let path = self.extension.path_from_extension(command.command.as_ref());
|
||||||
.host
|
|
||||||
.path_from_extension(&self.extension.manifest.id, command.command.as_ref());
|
|
||||||
|
|
||||||
// TODO: This should now be done via the `zed::make_file_executable` function in
|
// TODO: This should now be done via the `zed::make_file_executable` function in
|
||||||
// Zed extension API, but we're leaving these existing usages in place temporarily
|
// Zed extension API, but we're leaving these existing usages in place temporarily
|
||||||
|
@ -104,8 +83,8 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
// We can remove once the following extension versions no longer see any use:
|
// We can remove once the following extension versions no longer see any use:
|
||||||
// - toml@0.0.2
|
// - toml@0.0.2
|
||||||
// - zig@0.0.1
|
// - zig@0.0.1
|
||||||
if ["toml", "zig"].contains(&self.extension.manifest.id.as_ref())
|
if ["toml", "zig"].contains(&self.extension.manifest().id.as_ref())
|
||||||
&& path.starts_with(&self.host.work_dir)
|
&& path.starts_with(&self.extension.work_dir())
|
||||||
{
|
{
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
{
|
{
|
||||||
|
@ -153,7 +132,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
||||||
let code_action_kinds = self
|
let code_action_kinds = self
|
||||||
.extension
|
.extension
|
||||||
.manifest
|
.manifest()
|
||||||
.language_servers
|
.language_servers
|
||||||
.get(&self.language_server_id)
|
.get(&self.language_server_id)
|
||||||
.and_then(|server| server.code_action_kinds.clone());
|
.and_then(|server| server.code_action_kinds.clone());
|
||||||
|
@ -174,14 +153,14 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
//
|
//
|
||||||
// We can remove once the following extension versions no longer see any use:
|
// We can remove once the following extension versions no longer see any use:
|
||||||
// - php@0.0.1
|
// - php@0.0.1
|
||||||
if self.extension.manifest.id.as_ref() == "php" {
|
if self.extension.manifest().id.as_ref() == "php" {
|
||||||
return HashMap::from_iter([("PHP".into(), "php".into())]);
|
return HashMap::from_iter([("PHP".into(), "php".into())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.extension
|
self.extension
|
||||||
.manifest
|
.manifest()
|
||||||
.language_servers
|
.language_servers
|
||||||
.get(&LanguageServerName(self.config.name.clone().into()))
|
.get(&self.language_server_id)
|
||||||
.map(|server| server.language_ids.clone())
|
.map(|server| server.language_ids.clone())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
@ -190,29 +169,14 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
) -> Result<Option<serde_json::Value>> {
|
) -> Result<Option<serde_json::Value>> {
|
||||||
let delegate = delegate.clone();
|
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
||||||
let json_options = self
|
let json_options = self
|
||||||
.extension
|
.extension
|
||||||
.call({
|
.language_server_initialization_options(
|
||||||
let this = self.clone();
|
self.language_server_id.clone(),
|
||||||
|extension, store| {
|
self.language_name.clone(),
|
||||||
async move {
|
delegate,
|
||||||
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
)
|
||||||
let resource = store.data_mut().table().push(delegate)?;
|
|
||||||
let options = extension
|
|
||||||
.call_language_server_initialization_options(
|
|
||||||
store,
|
|
||||||
&this.language_server_id,
|
|
||||||
&this.config,
|
|
||||||
resource,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
.map_err(|e| anyhow!("{}", e))?;
|
|
||||||
anyhow::Ok(options)
|
|
||||||
}
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
Ok(if let Some(json_options) = json_options {
|
Ok(if let Some(json_options) = json_options {
|
||||||
serde_json::from_str(&json_options).with_context(|| {
|
serde_json::from_str(&json_options).with_context(|| {
|
||||||
|
@ -229,32 +193,14 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Arc<dyn LanguageToolchainStore>,
|
||||||
_cx: &mut AsyncAppContext,
|
_cx: &mut AsyncAppContext,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let delegate = delegate.clone();
|
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
||||||
let json_options: Option<String> = self
|
let json_options: Option<String> = self
|
||||||
.extension
|
.extension
|
||||||
.call({
|
.language_server_workspace_configuration(self.language_server_id.clone(), delegate)
|
||||||
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(
|
|
||||||
store,
|
|
||||||
&this.language_server_id,
|
|
||||||
resource,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
.map_err(|e| anyhow!("{}", e))?;
|
|
||||||
anyhow::Ok(options)
|
|
||||||
}
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
Ok(if let Some(json_options) = json_options {
|
Ok(if let Some(json_options) = json_options {
|
||||||
serde_json::from_str(&json_options).with_context(|| {
|
serde_json::from_str(&json_options).with_context(|| {
|
||||||
format!("failed to parse initialization_options from extension: {json_options}")
|
format!("failed to parse workspace_configuration from extension: {json_options}")
|
||||||
})?
|
})?
|
||||||
} else {
|
} else {
|
||||||
serde_json::json!({})
|
serde_json::json!({})
|
||||||
|
@ -268,30 +214,16 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
) -> Result<Vec<Option<CodeLabel>>> {
|
) -> Result<Vec<Option<CodeLabel>>> {
|
||||||
let completions = completions
|
let completions = completions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|completion| wit::Completion::from(completion.clone()))
|
.cloned()
|
||||||
|
.map(lsp_completion_to_extension)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let labels = self
|
let labels = self
|
||||||
.extension
|
.extension
|
||||||
.call({
|
.labels_for_completions(self.language_server_id.clone(), completions)
|
||||||
let this = self.clone();
|
|
||||||
|extension, store| {
|
|
||||||
async move {
|
|
||||||
extension
|
|
||||||
.call_labels_for_completions(
|
|
||||||
store,
|
|
||||||
&this.language_server_id,
|
|
||||||
completions,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
.map_err(|e| anyhow!("{}", e))
|
|
||||||
}
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(labels_from_wit(labels, language))
|
Ok(labels_from_extension(labels, language))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn labels_for_symbols(
|
async fn labels_for_symbols(
|
||||||
|
@ -302,34 +234,29 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
let symbols = symbols
|
let symbols = symbols
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|(name, kind)| wit::Symbol {
|
.map(|(name, kind)| extension::Symbol {
|
||||||
name,
|
name,
|
||||||
kind: kind.into(),
|
kind: lsp_symbol_kind_to_extension(kind),
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let labels = self
|
let labels = self
|
||||||
.extension
|
.extension
|
||||||
.call({
|
.labels_for_symbols(self.language_server_id.clone(), symbols)
|
||||||
let this = self.clone();
|
|
||||||
|extension, store| {
|
|
||||||
async move {
|
|
||||||
extension
|
|
||||||
.call_labels_for_symbols(store, &this.language_server_id, symbols)
|
|
||||||
.await?
|
|
||||||
.map_err(|e| anyhow!("{}", e))
|
|
||||||
}
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(labels_from_wit(labels, language))
|
Ok(labels_from_extension(
|
||||||
|
labels
|
||||||
|
.into_iter()
|
||||||
|
.map(|label| label.map(Into::into))
|
||||||
|
.collect(),
|
||||||
|
language,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn labels_from_wit(
|
fn labels_from_extension(
|
||||||
labels: Vec<Option<wit::CodeLabel>>,
|
labels: Vec<Option<extension::CodeLabel>>,
|
||||||
language: &Arc<Language>,
|
language: &Arc<Language>,
|
||||||
) -> Vec<Option<CodeLabel>> {
|
) -> Vec<Option<CodeLabel>> {
|
||||||
labels
|
labels
|
||||||
|
@ -347,7 +274,7 @@ fn labels_from_wit(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_code_label(
|
fn build_code_label(
|
||||||
label: &wit::CodeLabel,
|
label: &extension::CodeLabel,
|
||||||
parsed_runs: &[(Range<usize>, HighlightId)],
|
parsed_runs: &[(Range<usize>, HighlightId)],
|
||||||
language: &Arc<Language>,
|
language: &Arc<Language>,
|
||||||
) -> Option<CodeLabel> {
|
) -> Option<CodeLabel> {
|
||||||
|
@ -356,8 +283,7 @@ fn build_code_label(
|
||||||
|
|
||||||
for span in &label.spans {
|
for span in &label.spans {
|
||||||
match span {
|
match span {
|
||||||
wit::CodeLabelSpan::CodeRange(range) => {
|
extension::CodeLabelSpan::CodeRange(range) => {
|
||||||
let range = Range::from(*range);
|
|
||||||
let code_span = &label.code.get(range.clone())?;
|
let code_span = &label.code.get(range.clone())?;
|
||||||
let mut input_ix = range.start;
|
let mut input_ix = range.start;
|
||||||
let mut output_ix = text.len();
|
let mut output_ix = text.len();
|
||||||
|
@ -383,7 +309,7 @@ fn build_code_label(
|
||||||
|
|
||||||
text.push_str(code_span);
|
text.push_str(code_span);
|
||||||
}
|
}
|
||||||
wit::CodeLabelSpan::Literal(span) => {
|
extension::CodeLabelSpan::Literal(span) => {
|
||||||
let highlight_id = language
|
let highlight_id = language
|
||||||
.grammar()
|
.grammar()
|
||||||
.zip(span.highlight_name.as_ref())
|
.zip(span.highlight_name.as_ref())
|
||||||
|
@ -398,7 +324,7 @@ fn build_code_label(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let filter_range = Range::from(label.filter_range);
|
let filter_range = label.filter_range.clone();
|
||||||
text.get(filter_range.clone())?;
|
text.get(filter_range.clone())?;
|
||||||
Some(CodeLabel {
|
Some(CodeLabel {
|
||||||
text,
|
text,
|
||||||
|
@ -407,109 +333,101 @@ fn build_code_label(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<wit::Range> for Range<usize> {
|
fn lsp_completion_to_extension(value: lsp::CompletionItem) -> extension::Completion {
|
||||||
fn from(range: wit::Range) -> Self {
|
extension::Completion {
|
||||||
let start = range.start as usize;
|
label: value.label,
|
||||||
let end = range.end as usize;
|
label_details: value
|
||||||
start..end
|
.label_details
|
||||||
|
.map(lsp_completion_item_label_details_to_extension),
|
||||||
|
detail: value.detail,
|
||||||
|
kind: value.kind.map(lsp_completion_item_kind_to_extension),
|
||||||
|
insert_text_format: value
|
||||||
|
.insert_text_format
|
||||||
|
.map(lsp_insert_text_format_to_extension),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<lsp::CompletionItem> for wit::Completion {
|
fn lsp_completion_item_label_details_to_extension(
|
||||||
fn from(value: lsp::CompletionItem) -> Self {
|
value: lsp::CompletionItemLabelDetails,
|
||||||
Self {
|
) -> extension::CompletionLabelDetails {
|
||||||
label: value.label,
|
extension::CompletionLabelDetails {
|
||||||
label_details: value.label_details.map(Into::into),
|
detail: value.detail,
|
||||||
detail: value.detail,
|
description: value.description,
|
||||||
kind: value.kind.map(Into::into),
|
|
||||||
insert_text_format: value.insert_text_format.map(Into::into),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<lsp::CompletionItemLabelDetails> for wit::CompletionLabelDetails {
|
fn lsp_completion_item_kind_to_extension(
|
||||||
fn from(value: lsp::CompletionItemLabelDetails) -> Self {
|
value: lsp::CompletionItemKind,
|
||||||
Self {
|
) -> extension::CompletionKind {
|
||||||
detail: value.detail,
|
match value {
|
||||||
description: value.description,
|
lsp::CompletionItemKind::TEXT => extension::CompletionKind::Text,
|
||||||
}
|
lsp::CompletionItemKind::METHOD => extension::CompletionKind::Method,
|
||||||
|
lsp::CompletionItemKind::FUNCTION => extension::CompletionKind::Function,
|
||||||
|
lsp::CompletionItemKind::CONSTRUCTOR => extension::CompletionKind::Constructor,
|
||||||
|
lsp::CompletionItemKind::FIELD => extension::CompletionKind::Field,
|
||||||
|
lsp::CompletionItemKind::VARIABLE => extension::CompletionKind::Variable,
|
||||||
|
lsp::CompletionItemKind::CLASS => extension::CompletionKind::Class,
|
||||||
|
lsp::CompletionItemKind::INTERFACE => extension::CompletionKind::Interface,
|
||||||
|
lsp::CompletionItemKind::MODULE => extension::CompletionKind::Module,
|
||||||
|
lsp::CompletionItemKind::PROPERTY => extension::CompletionKind::Property,
|
||||||
|
lsp::CompletionItemKind::UNIT => extension::CompletionKind::Unit,
|
||||||
|
lsp::CompletionItemKind::VALUE => extension::CompletionKind::Value,
|
||||||
|
lsp::CompletionItemKind::ENUM => extension::CompletionKind::Enum,
|
||||||
|
lsp::CompletionItemKind::KEYWORD => extension::CompletionKind::Keyword,
|
||||||
|
lsp::CompletionItemKind::SNIPPET => extension::CompletionKind::Snippet,
|
||||||
|
lsp::CompletionItemKind::COLOR => extension::CompletionKind::Color,
|
||||||
|
lsp::CompletionItemKind::FILE => extension::CompletionKind::File,
|
||||||
|
lsp::CompletionItemKind::REFERENCE => extension::CompletionKind::Reference,
|
||||||
|
lsp::CompletionItemKind::FOLDER => extension::CompletionKind::Folder,
|
||||||
|
lsp::CompletionItemKind::ENUM_MEMBER => extension::CompletionKind::EnumMember,
|
||||||
|
lsp::CompletionItemKind::CONSTANT => extension::CompletionKind::Constant,
|
||||||
|
lsp::CompletionItemKind::STRUCT => extension::CompletionKind::Struct,
|
||||||
|
lsp::CompletionItemKind::EVENT => extension::CompletionKind::Event,
|
||||||
|
lsp::CompletionItemKind::OPERATOR => extension::CompletionKind::Operator,
|
||||||
|
lsp::CompletionItemKind::TYPE_PARAMETER => extension::CompletionKind::TypeParameter,
|
||||||
|
_ => extension::CompletionKind::Other(extract_int(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<lsp::CompletionItemKind> for wit::CompletionKind {
|
fn lsp_insert_text_format_to_extension(
|
||||||
fn from(value: lsp::CompletionItemKind) -> Self {
|
value: lsp::InsertTextFormat,
|
||||||
match value {
|
) -> extension::InsertTextFormat {
|
||||||
lsp::CompletionItemKind::TEXT => Self::Text,
|
match value {
|
||||||
lsp::CompletionItemKind::METHOD => Self::Method,
|
lsp::InsertTextFormat::PLAIN_TEXT => extension::InsertTextFormat::PlainText,
|
||||||
lsp::CompletionItemKind::FUNCTION => Self::Function,
|
lsp::InsertTextFormat::SNIPPET => extension::InsertTextFormat::Snippet,
|
||||||
lsp::CompletionItemKind::CONSTRUCTOR => Self::Constructor,
|
_ => extension::InsertTextFormat::Other(extract_int(value)),
|
||||||
lsp::CompletionItemKind::FIELD => Self::Field,
|
|
||||||
lsp::CompletionItemKind::VARIABLE => Self::Variable,
|
|
||||||
lsp::CompletionItemKind::CLASS => Self::Class,
|
|
||||||
lsp::CompletionItemKind::INTERFACE => Self::Interface,
|
|
||||||
lsp::CompletionItemKind::MODULE => Self::Module,
|
|
||||||
lsp::CompletionItemKind::PROPERTY => Self::Property,
|
|
||||||
lsp::CompletionItemKind::UNIT => Self::Unit,
|
|
||||||
lsp::CompletionItemKind::VALUE => Self::Value,
|
|
||||||
lsp::CompletionItemKind::ENUM => Self::Enum,
|
|
||||||
lsp::CompletionItemKind::KEYWORD => Self::Keyword,
|
|
||||||
lsp::CompletionItemKind::SNIPPET => Self::Snippet,
|
|
||||||
lsp::CompletionItemKind::COLOR => Self::Color,
|
|
||||||
lsp::CompletionItemKind::FILE => Self::File,
|
|
||||||
lsp::CompletionItemKind::REFERENCE => Self::Reference,
|
|
||||||
lsp::CompletionItemKind::FOLDER => Self::Folder,
|
|
||||||
lsp::CompletionItemKind::ENUM_MEMBER => Self::EnumMember,
|
|
||||||
lsp::CompletionItemKind::CONSTANT => Self::Constant,
|
|
||||||
lsp::CompletionItemKind::STRUCT => Self::Struct,
|
|
||||||
lsp::CompletionItemKind::EVENT => Self::Event,
|
|
||||||
lsp::CompletionItemKind::OPERATOR => Self::Operator,
|
|
||||||
lsp::CompletionItemKind::TYPE_PARAMETER => Self::TypeParameter,
|
|
||||||
_ => Self::Other(extract_int(value)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<lsp::InsertTextFormat> for wit::InsertTextFormat {
|
fn lsp_symbol_kind_to_extension(value: lsp::SymbolKind) -> extension::SymbolKind {
|
||||||
fn from(value: lsp::InsertTextFormat) -> Self {
|
match value {
|
||||||
match value {
|
lsp::SymbolKind::FILE => extension::SymbolKind::File,
|
||||||
lsp::InsertTextFormat::PLAIN_TEXT => Self::PlainText,
|
lsp::SymbolKind::MODULE => extension::SymbolKind::Module,
|
||||||
lsp::InsertTextFormat::SNIPPET => Self::Snippet,
|
lsp::SymbolKind::NAMESPACE => extension::SymbolKind::Namespace,
|
||||||
_ => Self::Other(extract_int(value)),
|
lsp::SymbolKind::PACKAGE => extension::SymbolKind::Package,
|
||||||
}
|
lsp::SymbolKind::CLASS => extension::SymbolKind::Class,
|
||||||
}
|
lsp::SymbolKind::METHOD => extension::SymbolKind::Method,
|
||||||
}
|
lsp::SymbolKind::PROPERTY => extension::SymbolKind::Property,
|
||||||
|
lsp::SymbolKind::FIELD => extension::SymbolKind::Field,
|
||||||
impl From<lsp::SymbolKind> for wit::SymbolKind {
|
lsp::SymbolKind::CONSTRUCTOR => extension::SymbolKind::Constructor,
|
||||||
fn from(value: lsp::SymbolKind) -> Self {
|
lsp::SymbolKind::ENUM => extension::SymbolKind::Enum,
|
||||||
match value {
|
lsp::SymbolKind::INTERFACE => extension::SymbolKind::Interface,
|
||||||
lsp::SymbolKind::FILE => Self::File,
|
lsp::SymbolKind::FUNCTION => extension::SymbolKind::Function,
|
||||||
lsp::SymbolKind::MODULE => Self::Module,
|
lsp::SymbolKind::VARIABLE => extension::SymbolKind::Variable,
|
||||||
lsp::SymbolKind::NAMESPACE => Self::Namespace,
|
lsp::SymbolKind::CONSTANT => extension::SymbolKind::Constant,
|
||||||
lsp::SymbolKind::PACKAGE => Self::Package,
|
lsp::SymbolKind::STRING => extension::SymbolKind::String,
|
||||||
lsp::SymbolKind::CLASS => Self::Class,
|
lsp::SymbolKind::NUMBER => extension::SymbolKind::Number,
|
||||||
lsp::SymbolKind::METHOD => Self::Method,
|
lsp::SymbolKind::BOOLEAN => extension::SymbolKind::Boolean,
|
||||||
lsp::SymbolKind::PROPERTY => Self::Property,
|
lsp::SymbolKind::ARRAY => extension::SymbolKind::Array,
|
||||||
lsp::SymbolKind::FIELD => Self::Field,
|
lsp::SymbolKind::OBJECT => extension::SymbolKind::Object,
|
||||||
lsp::SymbolKind::CONSTRUCTOR => Self::Constructor,
|
lsp::SymbolKind::KEY => extension::SymbolKind::Key,
|
||||||
lsp::SymbolKind::ENUM => Self::Enum,
|
lsp::SymbolKind::NULL => extension::SymbolKind::Null,
|
||||||
lsp::SymbolKind::INTERFACE => Self::Interface,
|
lsp::SymbolKind::ENUM_MEMBER => extension::SymbolKind::EnumMember,
|
||||||
lsp::SymbolKind::FUNCTION => Self::Function,
|
lsp::SymbolKind::STRUCT => extension::SymbolKind::Struct,
|
||||||
lsp::SymbolKind::VARIABLE => Self::Variable,
|
lsp::SymbolKind::EVENT => extension::SymbolKind::Event,
|
||||||
lsp::SymbolKind::CONSTANT => Self::Constant,
|
lsp::SymbolKind::OPERATOR => extension::SymbolKind::Operator,
|
||||||
lsp::SymbolKind::STRING => Self::String,
|
lsp::SymbolKind::TYPE_PARAMETER => extension::SymbolKind::TypeParameter,
|
||||||
lsp::SymbolKind::NUMBER => Self::Number,
|
_ => extension::SymbolKind::Other(extract_int(value)),
|
||||||
lsp::SymbolKind::BOOLEAN => Self::Boolean,
|
|
||||||
lsp::SymbolKind::ARRAY => Self::Array,
|
|
||||||
lsp::SymbolKind::OBJECT => Self::Object,
|
|
||||||
lsp::SymbolKind::KEY => Self::Key,
|
|
||||||
lsp::SymbolKind::NULL => Self::Null,
|
|
||||||
lsp::SymbolKind::ENUM_MEMBER => Self::EnumMember,
|
|
||||||
lsp::SymbolKind::STRUCT => Self::Struct,
|
|
||||||
lsp::SymbolKind::EVENT => Self::Event,
|
|
||||||
lsp::SymbolKind::OPERATOR => Self::Operator,
|
|
||||||
lsp::SymbolKind::TYPE_PARAMETER => Self::TypeParameter,
|
|
||||||
_ => Self::Other(extract_int(value)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,21 +454,14 @@ fn test_build_code_label() {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let label = build_code_label(
|
let label = build_code_label(
|
||||||
&wit::CodeLabel {
|
&extension::CodeLabel {
|
||||||
spans: vec![
|
spans: vec![
|
||||||
wit::CodeLabelSpan::CodeRange(wit::Range {
|
extension::CodeLabelSpan::CodeRange(code.find("pqrs").unwrap()..code.len()),
|
||||||
start: code.find("pqrs").unwrap() as u32,
|
extension::CodeLabelSpan::CodeRange(
|
||||||
end: code.len() as u32,
|
code.find(": fn").unwrap()..code.find(" = ").unwrap(),
|
||||||
}),
|
),
|
||||||
wit::CodeLabelSpan::CodeRange(wit::Range {
|
|
||||||
start: code.find(": fn").unwrap() as u32,
|
|
||||||
end: code.find(" = ").unwrap() as u32,
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
filter_range: wit::Range {
|
filter_range: 0.."pqrs.tuv".len(),
|
||||||
start: 0,
|
|
||||||
end: "pqrs.tuv".len() as u32,
|
|
||||||
},
|
|
||||||
code,
|
code,
|
||||||
},
|
},
|
||||||
&code_runs,
|
&code_runs,
|
||||||
|
@ -588,21 +499,14 @@ fn test_build_code_label_with_invalid_ranges() {
|
||||||
// A span uses a code range that is invalid because it starts inside of
|
// A span uses a code range that is invalid because it starts inside of
|
||||||
// a multi-byte character.
|
// a multi-byte character.
|
||||||
let label = build_code_label(
|
let label = build_code_label(
|
||||||
&wit::CodeLabel {
|
&extension::CodeLabel {
|
||||||
spans: vec![
|
spans: vec![
|
||||||
wit::CodeLabelSpan::CodeRange(wit::Range {
|
extension::CodeLabelSpan::CodeRange(
|
||||||
start: code.find('B').unwrap() as u32,
|
code.find('B').unwrap()..code.find(" = ").unwrap(),
|
||||||
end: code.find(" = ").unwrap() as u32,
|
),
|
||||||
}),
|
extension::CodeLabelSpan::CodeRange((code.find('🏀').unwrap() + 1)..code.len()),
|
||||||
wit::CodeLabelSpan::CodeRange(wit::Range {
|
|
||||||
start: code.find('🏀').unwrap() as u32 + 1,
|
|
||||||
end: code.len() as u32,
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
filter_range: wit::Range {
|
filter_range: 0.."B".len(),
|
||||||
start: 0,
|
|
||||||
end: "B".len() as u32,
|
|
||||||
},
|
|
||||||
code,
|
code,
|
||||||
},
|
},
|
||||||
&code_runs,
|
&code_runs,
|
||||||
|
@ -612,12 +516,14 @@ fn test_build_code_label_with_invalid_ranges() {
|
||||||
|
|
||||||
// Filter range extends beyond actual text
|
// Filter range extends beyond actual text
|
||||||
let label = build_code_label(
|
let label = build_code_label(
|
||||||
&wit::CodeLabel {
|
&extension::CodeLabel {
|
||||||
spans: vec![wit::CodeLabelSpan::Literal(wit::CodeLabelSpanLiteral {
|
spans: vec![extension::CodeLabelSpan::Literal(
|
||||||
text: "abc".into(),
|
extension::CodeLabelSpanLiteral {
|
||||||
highlight_name: Some("type".into()),
|
text: "abc".into(),
|
||||||
})],
|
highlight_name: Some("type".into()),
|
||||||
filter_range: wit::Range { start: 0, end: 5 },
|
},
|
||||||
|
)],
|
||||||
|
filter_range: 0..5,
|
||||||
code: String::new(),
|
code: String::new(),
|
||||||
},
|
},
|
||||||
&code_runs,
|
&code_runs,
|
||||||
|
|
|
@ -4,8 +4,8 @@ use crate::{ExtensionManifest, ExtensionRegistrationHooks};
|
||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use extension::{
|
use extension::{
|
||||||
KeyValueStoreDelegate, SlashCommand, SlashCommandArgumentCompletion, SlashCommandOutput,
|
CodeLabel, Command, Completion, KeyValueStoreDelegate, SlashCommand,
|
||||||
WorktreeDelegate,
|
SlashCommandArgumentCompletion, SlashCommandOutput, Symbol, WorktreeDelegate,
|
||||||
};
|
};
|
||||||
use fs::{normalize_path, Fs};
|
use fs::{normalize_path, Fs};
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
|
@ -19,6 +19,8 @@ use futures::{
|
||||||
};
|
};
|
||||||
use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
|
use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
|
||||||
use http_client::HttpClient;
|
use http_client::HttpClient;
|
||||||
|
use language::LanguageName;
|
||||||
|
use lsp::LanguageServerName;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use release_channel::ReleaseChannel;
|
use release_channel::ReleaseChannel;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
|
@ -65,6 +67,132 @@ impl extension::Extension for WasmExtension {
|
||||||
self.work_dir.clone()
|
self.work_dir.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn language_server_command(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
language_name: LanguageName,
|
||||||
|
worktree: Arc<dyn WorktreeDelegate>,
|
||||||
|
) -> Result<Command> {
|
||||||
|
self.call(|extension, store| {
|
||||||
|
async move {
|
||||||
|
let resource = store.data_mut().table().push(worktree)?;
|
||||||
|
let command = extension
|
||||||
|
.call_language_server_command(
|
||||||
|
store,
|
||||||
|
&language_server_id,
|
||||||
|
&language_name,
|
||||||
|
resource,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.map_err(|err| anyhow!("{err}"))?;
|
||||||
|
|
||||||
|
Ok(command.into())
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn language_server_initialization_options(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
language_name: LanguageName,
|
||||||
|
worktree: Arc<dyn WorktreeDelegate>,
|
||||||
|
) -> Result<Option<String>> {
|
||||||
|
self.call(|extension, store| {
|
||||||
|
async move {
|
||||||
|
let resource = store.data_mut().table().push(worktree)?;
|
||||||
|
let options = extension
|
||||||
|
.call_language_server_initialization_options(
|
||||||
|
store,
|
||||||
|
&language_server_id,
|
||||||
|
&language_name,
|
||||||
|
resource,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.map_err(|err| anyhow!("{err}"))?;
|
||||||
|
anyhow::Ok(options)
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn language_server_workspace_configuration(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
worktree: Arc<dyn WorktreeDelegate>,
|
||||||
|
) -> Result<Option<String>> {
|
||||||
|
self.call(|extension, store| {
|
||||||
|
async move {
|
||||||
|
let resource = store.data_mut().table().push(worktree)?;
|
||||||
|
let options = extension
|
||||||
|
.call_language_server_workspace_configuration(
|
||||||
|
store,
|
||||||
|
&language_server_id,
|
||||||
|
resource,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.map_err(|err| anyhow!("{err}"))?;
|
||||||
|
anyhow::Ok(options)
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn labels_for_completions(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
completions: Vec<Completion>,
|
||||||
|
) -> Result<Vec<Option<CodeLabel>>> {
|
||||||
|
self.call(|extension, store| {
|
||||||
|
async move {
|
||||||
|
let labels = extension
|
||||||
|
.call_labels_for_completions(
|
||||||
|
store,
|
||||||
|
&language_server_id,
|
||||||
|
completions.into_iter().map(Into::into).collect(),
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.map_err(|err| anyhow!("{err}"))?;
|
||||||
|
|
||||||
|
Ok(labels
|
||||||
|
.into_iter()
|
||||||
|
.map(|label| label.map(Into::into))
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn labels_for_symbols(
|
||||||
|
&self,
|
||||||
|
language_server_id: LanguageServerName,
|
||||||
|
symbols: Vec<Symbol>,
|
||||||
|
) -> Result<Vec<Option<CodeLabel>>> {
|
||||||
|
self.call(|extension, store| {
|
||||||
|
async move {
|
||||||
|
let labels = extension
|
||||||
|
.call_labels_for_symbols(
|
||||||
|
store,
|
||||||
|
&language_server_id,
|
||||||
|
symbols.into_iter().map(Into::into).collect(),
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.map_err(|err| anyhow!("{err}"))?;
|
||||||
|
|
||||||
|
Ok(labels
|
||||||
|
.into_iter()
|
||||||
|
.map(|label| label.map(Into::into))
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn complete_slash_command_argument(
|
async fn complete_slash_command_argument(
|
||||||
&self,
|
&self,
|
||||||
command: SlashCommand,
|
command: SlashCommand,
|
||||||
|
@ -255,7 +383,7 @@ impl WasmHost {
|
||||||
|
|
||||||
Ok(WasmExtension {
|
Ok(WasmExtension {
|
||||||
manifest: manifest.clone(),
|
manifest: manifest.clone(),
|
||||||
work_dir: this.work_dir.clone().into(),
|
work_dir: this.work_dir.join(manifest.id.as_ref()).into(),
|
||||||
tx,
|
tx,
|
||||||
zed_api_version,
|
zed_api_version,
|
||||||
})
|
})
|
||||||
|
@ -286,11 +414,6 @@ impl WasmHost {
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_from_extension(&self, id: &Arc<str>, path: &Path) -> PathBuf {
|
|
||||||
let extension_work_dir = self.work_dir.join(id.as_ref());
|
|
||||||
normalize_path(&extension_work_dir.join(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn writeable_path_from_extension(&self, id: &Arc<str>, path: &Path) -> Result<PathBuf> {
|
pub fn writeable_path_from_extension(&self, id: &Arc<str>, path: &Path) -> Result<PathBuf> {
|
||||||
let extension_work_dir = self.work_dir.join(id.as_ref());
|
let extension_work_dir = self.work_dir.join(id.as_ref());
|
||||||
let path = normalize_path(&extension_work_dir.join(path));
|
let path = normalize_path(&extension_work_dir.join(path));
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod since_v0_0_6;
|
||||||
mod since_v0_1_0;
|
mod since_v0_1_0;
|
||||||
mod since_v0_2_0;
|
mod since_v0_2_0;
|
||||||
use extension::{KeyValueStoreDelegate, WorktreeDelegate};
|
use extension::{KeyValueStoreDelegate, WorktreeDelegate};
|
||||||
|
use language::LanguageName;
|
||||||
use lsp::LanguageServerName;
|
use lsp::LanguageServerName;
|
||||||
use release_channel::ReleaseChannel;
|
use release_channel::ReleaseChannel;
|
||||||
use since_v0_2_0 as latest;
|
use since_v0_2_0 as latest;
|
||||||
|
@ -163,7 +164,7 @@ impl Extension {
|
||||||
&self,
|
&self,
|
||||||
store: &mut Store<WasmState>,
|
store: &mut Store<WasmState>,
|
||||||
language_server_id: &LanguageServerName,
|
language_server_id: &LanguageServerName,
|
||||||
config: &LanguageServerConfig,
|
language_name: &LanguageName,
|
||||||
resource: Resource<Arc<dyn WorktreeDelegate>>,
|
resource: Resource<Arc<dyn WorktreeDelegate>>,
|
||||||
) -> Result<Result<Command, String>> {
|
) -> Result<Result<Command, String>> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -180,11 +181,26 @@ impl Extension {
|
||||||
.await?
|
.await?
|
||||||
.map(|command| command.into())),
|
.map(|command| command.into())),
|
||||||
Extension::V004(ext) => Ok(ext
|
Extension::V004(ext) => Ok(ext
|
||||||
.call_language_server_command(store, config, resource)
|
.call_language_server_command(
|
||||||
|
store,
|
||||||
|
&LanguageServerConfig {
|
||||||
|
name: language_server_id.0.to_string(),
|
||||||
|
language_name: language_name.to_string(),
|
||||||
|
},
|
||||||
|
resource,
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
.map(|command| command.into())),
|
.map(|command| command.into())),
|
||||||
Extension::V001(ext) => Ok(ext
|
Extension::V001(ext) => Ok(ext
|
||||||
.call_language_server_command(store, &config.clone().into(), resource)
|
.call_language_server_command(
|
||||||
|
store,
|
||||||
|
&LanguageServerConfig {
|
||||||
|
name: language_server_id.0.to_string(),
|
||||||
|
language_name: language_name.to_string(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
resource,
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
.map(|command| command.into())),
|
.map(|command| command.into())),
|
||||||
}
|
}
|
||||||
|
@ -194,7 +210,7 @@ impl Extension {
|
||||||
&self,
|
&self,
|
||||||
store: &mut Store<WasmState>,
|
store: &mut Store<WasmState>,
|
||||||
language_server_id: &LanguageServerName,
|
language_server_id: &LanguageServerName,
|
||||||
config: &LanguageServerConfig,
|
language_name: &LanguageName,
|
||||||
resource: Resource<Arc<dyn WorktreeDelegate>>,
|
resource: Resource<Arc<dyn WorktreeDelegate>>,
|
||||||
) -> Result<Result<Option<String>, String>> {
|
) -> Result<Result<Option<String>, String>> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -223,13 +239,24 @@ impl Extension {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
Extension::V004(ext) => {
|
Extension::V004(ext) => {
|
||||||
ext.call_language_server_initialization_options(store, config, resource)
|
ext.call_language_server_initialization_options(
|
||||||
.await
|
store,
|
||||||
|
&LanguageServerConfig {
|
||||||
|
name: language_server_id.0.to_string(),
|
||||||
|
language_name: language_name.to_string(),
|
||||||
|
},
|
||||||
|
resource,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
Extension::V001(ext) => {
|
Extension::V001(ext) => {
|
||||||
ext.call_language_server_initialization_options(
|
ext.call_language_server_initialization_options(
|
||||||
store,
|
store,
|
||||||
&config.clone().into(),
|
&LanguageServerConfig {
|
||||||
|
name: language_server_id.0.to_string(),
|
||||||
|
language_name: language_name.to_string(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
resource,
|
resource,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::wasm_host::wit::since_v0_2_0::slash_command::SlashCommandOutputSection;
|
use crate::wasm_host::wit::since_v0_2_0::slash_command::SlashCommandOutputSection;
|
||||||
|
use crate::wasm_host::wit::{CompletionKind, CompletionLabelDetails, InsertTextFormat, SymbolKind};
|
||||||
use crate::wasm_host::{wit::ToWasmtimeResult, WasmState};
|
use crate::wasm_host::{wit::ToWasmtimeResult, WasmState};
|
||||||
use ::http_client::{AsyncBody, HttpRequestExt};
|
use ::http_client::{AsyncBody, HttpRequestExt};
|
||||||
use ::settings::{Settings, WorktreeId};
|
use ::settings::{Settings, WorktreeId};
|
||||||
|
@ -55,6 +56,159 @@ pub fn linker() -> &'static Linker<WasmState> {
|
||||||
LINKER.get_or_init(|| super::new_linker(Extension::add_to_linker))
|
LINKER.get_or_init(|| super::new_linker(Extension::add_to_linker))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Range> for std::ops::Range<usize> {
|
||||||
|
fn from(range: Range) -> Self {
|
||||||
|
let start = range.start as usize;
|
||||||
|
let end = range.end as usize;
|
||||||
|
start..end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Command> for extension::Command {
|
||||||
|
fn from(value: Command) -> Self {
|
||||||
|
Self {
|
||||||
|
command: value.command,
|
||||||
|
args: value.args,
|
||||||
|
env: value.env,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeLabel> for extension::CodeLabel {
|
||||||
|
fn from(value: CodeLabel) -> Self {
|
||||||
|
Self {
|
||||||
|
code: value.code,
|
||||||
|
spans: value.spans.into_iter().map(Into::into).collect(),
|
||||||
|
filter_range: value.filter_range.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeLabelSpan> for extension::CodeLabelSpan {
|
||||||
|
fn from(value: CodeLabelSpan) -> Self {
|
||||||
|
match value {
|
||||||
|
CodeLabelSpan::CodeRange(range) => Self::CodeRange(range.into()),
|
||||||
|
CodeLabelSpan::Literal(literal) => Self::Literal(literal.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeLabelSpanLiteral> for extension::CodeLabelSpanLiteral {
|
||||||
|
fn from(value: CodeLabelSpanLiteral) -> Self {
|
||||||
|
Self {
|
||||||
|
text: value.text,
|
||||||
|
highlight_name: value.highlight_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<extension::Completion> for Completion {
|
||||||
|
fn from(value: extension::Completion) -> Self {
|
||||||
|
Self {
|
||||||
|
label: value.label,
|
||||||
|
label_details: value.label_details.map(Into::into),
|
||||||
|
detail: value.detail,
|
||||||
|
kind: value.kind.map(Into::into),
|
||||||
|
insert_text_format: value.insert_text_format.map(Into::into),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<extension::CompletionLabelDetails> for CompletionLabelDetails {
|
||||||
|
fn from(value: extension::CompletionLabelDetails) -> Self {
|
||||||
|
Self {
|
||||||
|
detail: value.detail,
|
||||||
|
description: value.description,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<extension::CompletionKind> for CompletionKind {
|
||||||
|
fn from(value: extension::CompletionKind) -> Self {
|
||||||
|
match value {
|
||||||
|
extension::CompletionKind::Text => Self::Text,
|
||||||
|
extension::CompletionKind::Method => Self::Method,
|
||||||
|
extension::CompletionKind::Function => Self::Function,
|
||||||
|
extension::CompletionKind::Constructor => Self::Constructor,
|
||||||
|
extension::CompletionKind::Field => Self::Field,
|
||||||
|
extension::CompletionKind::Variable => Self::Variable,
|
||||||
|
extension::CompletionKind::Class => Self::Class,
|
||||||
|
extension::CompletionKind::Interface => Self::Interface,
|
||||||
|
extension::CompletionKind::Module => Self::Module,
|
||||||
|
extension::CompletionKind::Property => Self::Property,
|
||||||
|
extension::CompletionKind::Unit => Self::Unit,
|
||||||
|
extension::CompletionKind::Value => Self::Value,
|
||||||
|
extension::CompletionKind::Enum => Self::Enum,
|
||||||
|
extension::CompletionKind::Keyword => Self::Keyword,
|
||||||
|
extension::CompletionKind::Snippet => Self::Snippet,
|
||||||
|
extension::CompletionKind::Color => Self::Color,
|
||||||
|
extension::CompletionKind::File => Self::File,
|
||||||
|
extension::CompletionKind::Reference => Self::Reference,
|
||||||
|
extension::CompletionKind::Folder => Self::Folder,
|
||||||
|
extension::CompletionKind::EnumMember => Self::EnumMember,
|
||||||
|
extension::CompletionKind::Constant => Self::Constant,
|
||||||
|
extension::CompletionKind::Struct => Self::Struct,
|
||||||
|
extension::CompletionKind::Event => Self::Event,
|
||||||
|
extension::CompletionKind::Operator => Self::Operator,
|
||||||
|
extension::CompletionKind::TypeParameter => Self::TypeParameter,
|
||||||
|
extension::CompletionKind::Other(value) => Self::Other(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<extension::InsertTextFormat> for InsertTextFormat {
|
||||||
|
fn from(value: extension::InsertTextFormat) -> Self {
|
||||||
|
match value {
|
||||||
|
extension::InsertTextFormat::PlainText => Self::PlainText,
|
||||||
|
extension::InsertTextFormat::Snippet => Self::Snippet,
|
||||||
|
extension::InsertTextFormat::Other(value) => Self::Other(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<extension::Symbol> for Symbol {
|
||||||
|
fn from(value: extension::Symbol) -> Self {
|
||||||
|
Self {
|
||||||
|
kind: value.kind.into(),
|
||||||
|
name: value.name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<extension::SymbolKind> for SymbolKind {
|
||||||
|
fn from(value: extension::SymbolKind) -> Self {
|
||||||
|
match value {
|
||||||
|
extension::SymbolKind::File => Self::File,
|
||||||
|
extension::SymbolKind::Module => Self::Module,
|
||||||
|
extension::SymbolKind::Namespace => Self::Namespace,
|
||||||
|
extension::SymbolKind::Package => Self::Package,
|
||||||
|
extension::SymbolKind::Class => Self::Class,
|
||||||
|
extension::SymbolKind::Method => Self::Method,
|
||||||
|
extension::SymbolKind::Property => Self::Property,
|
||||||
|
extension::SymbolKind::Field => Self::Field,
|
||||||
|
extension::SymbolKind::Constructor => Self::Constructor,
|
||||||
|
extension::SymbolKind::Enum => Self::Enum,
|
||||||
|
extension::SymbolKind::Interface => Self::Interface,
|
||||||
|
extension::SymbolKind::Function => Self::Function,
|
||||||
|
extension::SymbolKind::Variable => Self::Variable,
|
||||||
|
extension::SymbolKind::Constant => Self::Constant,
|
||||||
|
extension::SymbolKind::String => Self::String,
|
||||||
|
extension::SymbolKind::Number => Self::Number,
|
||||||
|
extension::SymbolKind::Boolean => Self::Boolean,
|
||||||
|
extension::SymbolKind::Array => Self::Array,
|
||||||
|
extension::SymbolKind::Object => Self::Object,
|
||||||
|
extension::SymbolKind::Key => Self::Key,
|
||||||
|
extension::SymbolKind::Null => Self::Null,
|
||||||
|
extension::SymbolKind::EnumMember => Self::EnumMember,
|
||||||
|
extension::SymbolKind::Struct => Self::Struct,
|
||||||
|
extension::SymbolKind::Event => Self::Event,
|
||||||
|
extension::SymbolKind::Operator => Self::Operator,
|
||||||
|
extension::SymbolKind::TypeParameter => Self::TypeParameter,
|
||||||
|
extension::SymbolKind::Other(value) => Self::Other(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<extension::SlashCommand> for SlashCommand {
|
impl From<extension::SlashCommand> for SlashCommand {
|
||||||
fn from(value: extension::SlashCommand) -> Self {
|
fn from(value: extension::SlashCommand) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -26,7 +26,6 @@ impl IndexedDocsProvider for ExtensionIndexedDocsProvider {
|
||||||
|
|
||||||
fn database_path(&self) -> PathBuf {
|
fn database_path(&self) -> PathBuf {
|
||||||
let mut database_path = PathBuf::from(self.extension.work_dir().as_ref());
|
let mut database_path = PathBuf::from(self.extension.work_dir().as_ref());
|
||||||
database_path.push(self.extension.manifest().id.as_ref());
|
|
||||||
database_path.push("docs");
|
database_path.push("docs");
|
||||||
database_path.push(format!("{}.0.mdb", self.id));
|
database_path.push(format!("{}.0.mdb", self.id));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue