Detailed changes
@@ -52,11 +52,9 @@ impl SlashCommand for ExtensionSlashCommand {
delegate: Arc<dyn LspAdapterDelegate>,
cx: &mut WindowContext,
) -> Task<Result<SlashCommandOutput>> {
- let command_name = SharedString::from(self.command.name.clone());
let argument = argument.map(|arg| arg.to_string());
- let text = cx.background_executor().spawn(async move {
- let output = self
- .extension
+ let output = cx.background_executor().spawn(async move {
+ self.extension
.call({
let this = self.clone();
move |extension, store| {
@@ -77,19 +75,21 @@ impl SlashCommand for ExtensionSlashCommand {
.boxed()
}
})
- .await?;
- output.ok_or_else(|| anyhow!("no output from command: {}", self.command.name))
+ .await
});
cx.foreground_executor().spawn(async move {
- let text = text.await?;
- let range = 0..text.len();
+ let output = output.await?;
Ok(SlashCommandOutput {
- text,
- sections: vec![SlashCommandOutputSection {
- range,
- icon: IconName::Code,
- label: command_name,
- }],
+ text: output.text,
+ sections: output
+ .sections
+ .into_iter()
+ .map(|section| SlashCommandOutputSection {
+ range: section.range.into(),
+ icon: IconName::Code,
+ label: section.label.into(),
+ })
+ .collect(),
run_commands_in_text: false,
})
})
@@ -6,7 +6,7 @@ use release_channel::ReleaseChannel;
use since_v0_0_7 as latest;
use super::{wasm_engine, WasmState};
-use anyhow::{Context, Result};
+use anyhow::{anyhow, Context, Result};
use language::{LanguageServerName, LspAdapterDelegate};
use semantic_version::SemanticVersion;
use std::{ops::RangeInclusive, sync::Arc};
@@ -19,6 +19,7 @@ use wasmtime::{
pub use latest::CodeLabelSpanLiteral;
pub use latest::{
zed::extension::lsp::{Completion, CompletionKind, InsertTextFormat, Symbol, SymbolKind},
+ zed::extension::slash_command::SlashCommandOutput,
CodeLabel, CodeLabelSpan, Command, Range, SlashCommand,
};
pub use since_v0_0_4::LanguageServerConfig;
@@ -262,13 +263,15 @@ impl Extension {
command: &SlashCommand,
argument: Option<&str>,
resource: Resource<Arc<dyn LspAdapterDelegate>>,
- ) -> Result<Result<Option<String>, String>> {
+ ) -> Result<Result<SlashCommandOutput, String>> {
match self {
Extension::V007(ext) => {
ext.call_run_slash_command(store, command, argument, resource)
.await
}
- Extension::V001(_) | Extension::V004(_) | Extension::V006(_) => Ok(Ok(None)),
+ Extension::V001(_) | Extension::V004(_) | Extension::V006(_) => {
+ Err(anyhow!("`run_slash_command` not available prior to v0.0.7"))
+ }
}
}
}
@@ -98,6 +98,9 @@ impl HostWorktree for WasmState {
}
}
+#[async_trait]
+impl common::Host for WasmState {}
+
#[async_trait]
impl nodejs::Host for WasmState {
async fn node_binary_path(&mut self) -> wasmtime::Result<Result<String, String>> {
@@ -24,7 +24,7 @@ pub use wit::{
npm_package_latest_version,
},
zed::extension::platform::{current_platform, Architecture, Os},
- zed::extension::slash_command::SlashCommand,
+ zed::extension::slash_command::{SlashCommand, SlashCommandOutput, SlashCommandOutputSection},
CodeLabel, CodeLabelSpan, CodeLabelSpanLiteral, Command, DownloadedFileType, EnvVars,
LanguageServerInstallationStatus, Range, Worktree,
};
@@ -114,8 +114,8 @@ pub trait Extension: Send + Sync {
_command: SlashCommand,
_argument: Option<String>,
_worktree: &Worktree,
- ) -> Result<Option<String>, String> {
- Ok(None)
+ ) -> Result<SlashCommandOutput, String> {
+ Err("`run_slash_command` not implemented".to_string())
}
}
@@ -229,7 +229,7 @@ impl wit::Guest for Component {
command: SlashCommand,
argument: Option<String>,
worktree: &Worktree,
- ) -> Result<Option<String>, String> {
+ ) -> Result<SlashCommandOutput, String> {
extension().run_slash_command(command, argument, worktree)
}
}
@@ -0,0 +1,9 @@
+interface common {
+ /// A (half-open) range (`[start, end)`).
+ record range {
+ /// The start of the range (inclusive).
+ start: u32,
+ /// The end of the range (exclusive).
+ end: u32,
+ }
+}
@@ -5,8 +5,9 @@ world extension {
import platform;
import nodejs;
+ use common.{range};
use lsp.{completion, symbol};
- use slash-command.{slash-command};
+ use slash-command.{slash-command, slash-command-output};
/// Initializes the extension.
export init-extension: func();
@@ -118,17 +119,9 @@ world extension {
highlight-name: option<string>,
}
- /// A (half-open) range (`[start, end)`).
- record range {
- /// The start of the range (inclusive).
- start: u32,
- /// The end of the range (exclusive).
- end: u32,
- }
-
export labels-for-completions: func(language-server-id: string, completions: list<completion>) -> result<list<option<code-label>>, string>;
export labels-for-symbols: func(language-server-id: string, symbols: list<symbol>) -> result<list<option<code-label>>, string>;
/// Runs the provided slash command.
- export run-slash-command: func(command: slash-command, argument: option<string>, worktree: borrow<worktree>) -> result<option<string>, string>;
+ export run-slash-command: func(command: slash-command, argument: option<string>, worktree: borrow<worktree>) -> result<slash-command-output, string>;
}
@@ -1,4 +1,6 @@
interface slash-command {
+ use common.{range};
+
/// A slash command for use in the Assistant.
record slash-command {
/// The name of the slash command.
@@ -10,4 +12,20 @@ interface slash-command {
/// Whether this slash command requires an argument.
requires-argument: bool,
}
+
+ /// The output of a slash command.
+ record slash-command-output {
+ /// The text produced by the slash command.
+ text: string,
+ /// The list of sections to show in the slash command placeholder.
+ sections: list<slash-command-output-section>,
+ }
+
+ /// A section in the slash command output.
+ record slash-command-output-section {
+ /// The range this section occupies.
+ range: range,
+ /// The label to display in the placeholder for this section.
+ label: string,
+ }
}
@@ -1,6 +1,9 @@
use std::fs;
use zed::lsp::CompletionKind;
-use zed::{CodeLabel, CodeLabelSpan, LanguageServerId, SlashCommand};
+use zed::{
+ CodeLabel, CodeLabelSpan, LanguageServerId, SlashCommand, SlashCommandOutput,
+ SlashCommandOutputSection,
+};
use zed_extension_api::{self as zed, Result};
struct GleamExtension {
@@ -148,18 +151,24 @@ impl zed::Extension for GleamExtension {
command: SlashCommand,
_argument: Option<String>,
worktree: &zed::Worktree,
- ) -> Result<Option<String>, String> {
+ ) -> Result<SlashCommandOutput, String> {
match command.name.as_str() {
"gleam-project" => {
- let mut message = String::new();
- message.push_str("You are in a Gleam project.\n");
+ let mut text = String::new();
+ text.push_str("You are in a Gleam project.\n");
if let Some(gleam_toml) = worktree.read_text_file("gleam.toml").ok() {
- message.push_str("The `gleam.toml` is as follows:\n");
- message.push_str(&gleam_toml);
+ text.push_str("The `gleam.toml` is as follows:\n");
+ text.push_str(&gleam_toml);
}
- Ok(Some(message))
+ Ok(SlashCommandOutput {
+ sections: vec![SlashCommandOutputSection {
+ range: (0..text.len()).into(),
+ label: "gleam-project".to_string(),
+ }],
+ text,
+ })
}
command => Err(format!("unknown slash command: \"{command}\"")),
}