From b764174e8b326b769b897c34558571f4af97c110 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 15 Aug 2024 12:50:30 -0400 Subject: [PATCH] docs: Add docs for defining slash commands in extensions (#16303) This PR adds docs for defining slash commands within extensions. Release Notes: - N/A --- docs/src/SUMMARY.md | 1 + docs/src/extensions.md | 1 + docs/src/extensions/developing-extensions.md | 5 +- docs/src/extensions/slash-commands.md | 135 +++++++++++++++++++ 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 docs/src/extensions/slash-commands.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 4d222f3d64..9ca879814a 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -38,6 +38,7 @@ - [Developing Extensions](./extensions/developing-extensions.md) - [Language Extensions](./extensions/languages.md) - [Theme Extensions](./extensions/themes.md) +- [Slash Commands](./extensions/slash-commands.md) # Language Support diff --git a/docs/src/extensions.md b/docs/src/extensions.md index 060c819ecb..ece7e88467 100644 --- a/docs/src/extensions.md +++ b/docs/src/extensions.md @@ -6,3 +6,4 @@ Zed lets you add new functionality using user-defined extensions. - [Developing Extensions](./extensions/developing-extensions.md) - [Developing Language Extensions](./extensions/languages.md) - [Developing Themes](./extensions/themes.md) + - [Developing Slash Commands](./extensions/slash-commands.md) diff --git a/docs/src/extensions/developing-extensions.md b/docs/src/extensions/developing-extensions.md index f6eabab301..bc39895405 100644 --- a/docs/src/extensions/developing-extensions.md +++ b/docs/src/extensions/developing-extensions.md @@ -6,6 +6,7 @@ Extensions can add the following capabilities to Zed: - [Languages](./languages.md) - [Themes](./themes.md) +- [Slash Commands](./slash-commands.md) ## Directory Structure of a Zed Extension @@ -22,10 +23,6 @@ description = "My cool extension" repository = "https://github.com/your-name/my-zed-extension" ``` - - In addition to this, there are several other optional files and directories that can be used to add functionality to a Zed extension. An example directory structure of an extension that provides all capabilities is as follows: ``` diff --git a/docs/src/extensions/slash-commands.md b/docs/src/extensions/slash-commands.md new file mode 100644 index 0000000000..badce926f1 --- /dev/null +++ b/docs/src/extensions/slash-commands.md @@ -0,0 +1,135 @@ +# Slash Commands + +Extensions may provide slash commands for use in the Assistant. + +## Defining slash commands + +A given extension may provide one or more slash commands. Each slash command must be registered in the `extension.toml`. + +For example, here is an extension that provides two slash commands: `/echo` and `/pick-one`: + +```toml +[slash_commands.echo] +description = "echoes the provided input" +requires_argument = true +tooltip_text = "" + +[slash_commands.pick-one] +description = "pick one of three options" +requires_argument = true +tooltip_text = "" +``` + +Each slash command may define the following properties: + +- `description`: A description of the slash command that will be shown when completing available commands. +- `requires_argument`: Indicates whether a slash command requires at least one argument to run. +- `tooltip_text`: Currently unused. + +## Implementing slash command behavior + +To implement behavior for your slash commands, implement `run_slash_command` for your extension. + +This method accepts the slash command that will be run, the list of arguments passed to it, and an optional `Worktree`. + +This method returns `SlashCommandOutput`, which contains the textual output of the command in the `text` field. The output may also define `SlashCommandOutputSection`s that contain ranges into the output. These sections are then rendered as creases in the Assistant's context editor. + +Your extension should `match` on the command name (without the leading `/`) and then execute behavior accordingly: + +```rs +impl zed::Extension for MyExtension { + fn run_slash_command( + &self, + command: SlashCommand, + args: Vec, + _worktree: Option<&Worktree>, + ) -> Result { + match command.name.as_str() { + "echo" => { + if args.is_empty() { + return Err("nothing to echo".to_string()); + } + + let text = args.join(" "); + + Ok(SlashCommandOutput { + sections: vec![SlashCommandOutputSection { + range: (0..text.len()).into(), + label: "Echo".to_string(), + }], + text, + }) + } + "pick-one" => { + let Some(selection) = args.first() else { + return Err("no option selected".to_string()); + }; + + match selection.as_str() { + "option-1" | "option-2" | "option-3" => {} + invalid_option => { + return Err(format!("{invalid_option} is not a valid option")); + } + } + + let text = format!("You chose {selection}."); + + Ok(SlashCommandOutput { + sections: vec![SlashCommandOutputSection { + range: (0..text.len()).into(), + label: format!("Pick One: {selection}"), + }], + text, + }) + } + command => Err(format!("unknown slash command: \"{command}\"")), + } + } +} +``` + +## Auto-completing slash command arguments + +For slash commands that have arguments, you may also choose to implement `complete_slash_command_argument` to provide completions for your slash commands. + +This method accepts the slash command that will be run and the list of arguments passed to it. It returns a list of `SlashCommandArgumentCompletion`s that will be shown in the completion menu. + +A `SlashCommandArgumentCompletion` consists of the following properties: + +- `label`: The label that will be shown in the completion menu. +- `new_text`: The text that will be inserted when the completion is accepted. +- `run_command`: Whether the slash command will be run when the completion is accepted. + +Once again, your extension should `match` on the command name (without the leading `/`) and return the desired argument completions: + +```rs +impl zed::Extension for MyExtension { + fn complete_slash_command_argument( + &self, + command: SlashCommand, + _args: Vec, + ) -> Result, String> { + match command.name.as_str() { + "echo" => Ok(vec![]), + "pick-one" => Ok(vec![ + SlashCommandArgumentCompletion { + label: "Option One".to_string(), + new_text: "option-1".to_string(), + run_command: true, + }, + SlashCommandArgumentCompletion { + label: "Option Two".to_string(), + new_text: "option-2".to_string(), + run_command: true, + }, + SlashCommandArgumentCompletion { + label: "Option Three".to_string(), + new_text: "option-3".to_string(), + run_command: true, + }, + ]), + command => Err(format!("unknown slash command: \"{command}\"")), + } + } +} +```