Extract slash commands to their own crate (#23261)

This PR extracts the slash command definitions out of the `assistant`
crate and into their own `assistant_slash_commands` crate.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-01-16 17:17:07 -05:00 committed by GitHub
parent 1a8303b020
commit 8030c0025a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 452 additions and 347 deletions

View file

@ -1,25 +1,22 @@
use crate::slash_command::file_command::codeblock_fence_for_path;
use crate::{
humanize_token_count,
prompt_library::open_prompt_library,
slash_command::{
default_command::DefaultSlashCommand,
docs_command::{DocsSlashCommand, DocsSlashCommandArgs},
file_command, SlashCommandCompletionProvider,
},
slash_command_picker,
terminal_inline_assistant::TerminalInlineAssistant,
Assist, AssistantPatch, AssistantPatchStatus, CacheStatus, ConfirmCommand, Content, Context,
ContextEvent, ContextId, ContextStore, ContextStoreEvent, CopyCode, CycleMessageRole,
DeployHistory, DeployPromptLibrary, Edit, InlineAssistant, InsertDraggedFiles,
InsertIntoEditor, InvokedSlashCommandId, InvokedSlashCommandStatus, Message, MessageId,
MessageMetadata, MessageStatus, NewContext, ParsedSlashCommand, PendingSlashCommandStatus,
QuoteSelection, RemoteContextMetadata, RequestType, SavedContextMetadata, Split, ToggleFocus,
humanize_token_count, prompt_library::open_prompt_library,
slash_command::SlashCommandCompletionProvider, slash_command_picker,
terminal_inline_assistant::TerminalInlineAssistant, Assist, AssistantPatch,
AssistantPatchStatus, CacheStatus, ConfirmCommand, Content, Context, ContextEvent, ContextId,
ContextStore, ContextStoreEvent, CopyCode, CycleMessageRole, DeployHistory,
DeployPromptLibrary, Edit, InlineAssistant, InsertDraggedFiles, InsertIntoEditor,
InvokedSlashCommandId, InvokedSlashCommandStatus, Message, MessageId, MessageMetadata,
MessageStatus, NewContext, ParsedSlashCommand, PendingSlashCommandStatus, QuoteSelection,
RemoteContextMetadata, RequestType, SavedContextMetadata, Split, ToggleFocus,
ToggleModelSelector,
};
use anyhow::Result;
use assistant_settings::{AssistantDockPosition, AssistantSettings};
use assistant_slash_command::{SlashCommand, SlashCommandOutputSection, SlashCommandWorkingSet};
use assistant_slash_commands::{
selections_creases, DefaultSlashCommand, DocsSlashCommand, DocsSlashCommandArgs,
FileSlashCommand,
};
use assistant_tool::ToolWorkingSet;
use client::{proto, zed_urls, Client, Status};
use collections::{hash_map, BTreeSet, HashMap, HashSet};
@ -3032,7 +3029,7 @@ impl ContextEditor {
cx.spawn(|_, mut cx| async move {
let (paths, dragged_file_worktrees) = paths.await;
let cmd_name = file_command::FileSlashCommand.name();
let cmd_name = FileSlashCommand.name();
context_editor_view
.update(&mut cx, |context_editor, cx| {
@ -3994,99 +3991,6 @@ fn find_surrounding_code_block(snapshot: &BufferSnapshot, offset: usize) -> Opti
None
}
pub fn selections_creases(
workspace: &mut workspace::Workspace,
cx: &mut ViewContext<Workspace>,
) -> Option<Vec<(String, String)>> {
let editor = workspace
.active_item(cx)
.and_then(|item| item.act_as::<Editor>(cx))?;
let mut creases = vec![];
editor.update(cx, |editor, cx| {
let selections = editor.selections.all_adjusted(cx);
let buffer = editor.buffer().read(cx).snapshot(cx);
for selection in selections {
let range = editor::ToOffset::to_offset(&selection.start, &buffer)
..editor::ToOffset::to_offset(&selection.end, &buffer);
let selected_text = buffer.text_for_range(range.clone()).collect::<String>();
if selected_text.is_empty() {
continue;
}
let start_language = buffer.language_at(range.start);
let end_language = buffer.language_at(range.end);
let language_name = if start_language == end_language {
start_language.map(|language| language.code_fence_block_name())
} else {
None
};
let language_name = language_name.as_deref().unwrap_or("");
let filename = buffer
.file_at(selection.start)
.map(|file| file.full_path(cx));
let text = if language_name == "markdown" {
selected_text
.lines()
.map(|line| format!("> {}", line))
.collect::<Vec<_>>()
.join("\n")
} else {
let start_symbols = buffer
.symbols_containing(selection.start, None)
.map(|(_, symbols)| symbols);
let end_symbols = buffer
.symbols_containing(selection.end, None)
.map(|(_, symbols)| symbols);
let outline_text =
if let Some((start_symbols, end_symbols)) = start_symbols.zip(end_symbols) {
Some(
start_symbols
.into_iter()
.zip(end_symbols)
.take_while(|(a, b)| a == b)
.map(|(a, _)| a.text)
.collect::<Vec<_>>()
.join(" > "),
)
} else {
None
};
let line_comment_prefix = start_language
.and_then(|l| l.default_scope().line_comment_prefixes().first().cloned());
let fence = codeblock_fence_for_path(
filename.as_deref(),
Some(selection.start.row..=selection.end.row),
);
if let Some((line_comment_prefix, outline_text)) =
line_comment_prefix.zip(outline_text)
{
let breadcrumb = format!("{line_comment_prefix}Excerpt from: {outline_text}\n");
format!("{fence}{breadcrumb}{selected_text}\n```")
} else {
format!("{fence}{selected_text}\n```")
}
};
let crease_title = if let Some(path) = filename {
let start_line = selection.start.row + 1;
let end_line = selection.end.row + 1;
if start_line == end_line {
format!("{}, Line {}", path.display(), start_line)
} else {
format!("{}, Lines {} to {}", path.display(), start_line, end_line)
}
} else {
"Quoted selection".to_string()
};
creases.push((text, crease_title));
}
});
Some(creases)
}
fn render_fold_icon_button(
editor: WeakView<Editor>,
icon: IconName,