Adjust design of the slash command picker (#19973)
This PR removes the quote selection icon button from the footer and adds it in the picker, and adds an icon field to each command entry. Final result looks like: https://github.com/user-attachments/assets/d177f1c1-b6f6-4652-9434-f6291b279e34 Release Notes: - N/A
This commit is contained in:
parent
f80eb264fb
commit
6d5784daa6
15 changed files with 185 additions and 110 deletions
1
assets/icons/wand.svg
Normal file
1
assets/icons/wand.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-wand"><path d="M15 4V2"/><path d="M15 16v-2"/><path d="M8 9h2"/><path d="M20 9h2"/><path d="M17.8 11.8 19 13"/><path d="M15 9h.01"/><path d="M17.8 6.2 19 5"/><path d="m3 21 9-9"/><path d="M12.2 6.2 11 5"/></svg>
|
After Width: | Height: | Size: 414 B |
|
@ -73,12 +73,11 @@ use std::{
|
||||||
};
|
};
|
||||||
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
|
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
|
||||||
use text::SelectionGoal;
|
use text::SelectionGoal;
|
||||||
use ui::TintColor;
|
|
||||||
use ui::{
|
use ui::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
utils::{format_distance_from_now, DateTimeType},
|
utils::{format_distance_from_now, DateTimeType},
|
||||||
Avatar, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem,
|
Avatar, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem,
|
||||||
ListItemSpacing, PopoverMenu, PopoverMenuHandle, Tooltip,
|
ListItemSpacing, PopoverMenu, PopoverMenuHandle, TintColor, Tooltip,
|
||||||
};
|
};
|
||||||
use util::{maybe, ResultExt};
|
use util::{maybe, ResultExt};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
|
@ -4006,13 +4005,7 @@ impl Render for ContextEditor {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let focus_handle = self
|
|
||||||
.workspace
|
|
||||||
.update(cx, |workspace, cx| {
|
|
||||||
Some(workspace.active_item_as::<Editor>(cx)?.focus_handle(cx))
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.flatten();
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.key_context("ContextEditor")
|
.key_context("ContextEditor")
|
||||||
.capture_action(cx.listener(ContextEditor::cancel))
|
.capture_action(cx.listener(ContextEditor::cancel))
|
||||||
|
@ -4060,28 +4053,7 @@ impl Render for ContextEditor {
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.child(render_inject_context_menu(cx.view().downgrade(), cx))
|
.child(render_inject_context_menu(cx.view().downgrade(), cx)),
|
||||||
.child(
|
|
||||||
IconButton::new("quote-button", IconName::Quote)
|
|
||||||
.icon_size(IconSize::Small)
|
|
||||||
.on_click(|_, cx| {
|
|
||||||
cx.dispatch_action(QuoteSelection.boxed_clone());
|
|
||||||
})
|
|
||||||
.tooltip(move |cx| {
|
|
||||||
cx.new_view(|cx| {
|
|
||||||
Tooltip::new("Insert Selection").key_binding(
|
|
||||||
focus_handle.as_ref().and_then(|handle| {
|
|
||||||
KeyBinding::for_action_in(
|
|
||||||
&QuoteSelection,
|
|
||||||
&handle,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.into()
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
@ -4376,6 +4348,7 @@ fn render_inject_context_menu(
|
||||||
Button::new("trigger", "Add Context")
|
Button::new("trigger", "Add Context")
|
||||||
.icon(IconName::Plus)
|
.icon(IconName::Plus)
|
||||||
.icon_size(IconSize::Small)
|
.icon_size(IconSize::Small)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
.icon_position(IconPosition::Start)
|
.icon_position(IconPosition::Start)
|
||||||
.tooltip(|cx| Tooltip::text("Type / to insert via keyboard", cx)),
|
.tooltip(|cx| Tooltip::text("Type / to insert via keyboard", cx)),
|
||||||
)
|
)
|
||||||
|
@ -4550,7 +4523,7 @@ impl Render for ContextEditorToolbarItem {
|
||||||
.w_full()
|
.w_full()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.child(Label::new("Insert Context"))
|
.child(Label::new("Add Context"))
|
||||||
.child(Label::new("/ command").color(Color::Muted))
|
.child(Label::new("/ command").color(Color::Muted))
|
||||||
.into_any()
|
.into_any()
|
||||||
},
|
},
|
||||||
|
@ -4574,7 +4547,7 @@ impl Render for ContextEditorToolbarItem {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.action("Insert Selection", QuoteSelection.boxed_clone())
|
.action("Add Selection", QuoteSelection.boxed_clone())
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -14,7 +14,7 @@ use language_model::{
|
||||||
use semantic_index::{FileSummary, SemanticDb};
|
use semantic_index::{FileSummary, SemanticDb};
|
||||||
use smol::channel;
|
use smol::channel;
|
||||||
use std::sync::{atomic::AtomicBool, Arc};
|
use std::sync::{atomic::AtomicBool, Arc};
|
||||||
use ui::{BorrowAppContext, WindowContext};
|
use ui::{prelude::*, BorrowAppContext, WindowContext};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
|
@ -37,6 +37,10 @@ impl SlashCommand for AutoCommand {
|
||||||
"Automatically infer what context to add".into()
|
"Automatically infer what context to add".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::Wand
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use gpui::{Task, WeakView, WindowContext};
|
||||||
use language::{BufferSnapshot, LspAdapterDelegate};
|
use language::{BufferSnapshot, LspAdapterDelegate};
|
||||||
use std::sync::{atomic::AtomicBool, Arc};
|
use std::sync::{atomic::AtomicBool, Arc};
|
||||||
use text::OffsetRangeExt;
|
use text::OffsetRangeExt;
|
||||||
|
use ui::prelude::*;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
pub(crate) struct DeltaSlashCommand;
|
pub(crate) struct DeltaSlashCommand;
|
||||||
|
@ -27,6 +28,10 @@ impl SlashCommand for DeltaSlashCommand {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::Diff
|
||||||
|
}
|
||||||
|
|
||||||
fn requires_argument(&self) -> bool {
|
fn requires_argument(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,10 @@ impl SlashCommand for DiagnosticsSlashCommand {
|
||||||
"Insert diagnostics".into()
|
"Insert diagnostics".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::XCircle
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ impl SlashCommand for FileSlashCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description(&self) -> String {
|
fn description(&self) -> String {
|
||||||
"Insert file".into()
|
"Insert file and/or directory".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
|
@ -128,6 +128,10 @@ impl SlashCommand for FileSlashCommand {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::File
|
||||||
|
}
|
||||||
|
|
||||||
fn complete_argument(
|
fn complete_argument(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
arguments: &[String],
|
arguments: &[String],
|
||||||
|
|
|
@ -24,7 +24,8 @@ use std::{
|
||||||
ops::DerefMut,
|
ops::DerefMut,
|
||||||
sync::{atomic::AtomicBool, Arc},
|
sync::{atomic::AtomicBool, Arc},
|
||||||
};
|
};
|
||||||
use ui::{BorrowAppContext as _, IconName};
|
|
||||||
|
use ui::prelude::*;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
pub struct ProjectSlashCommand {
|
pub struct ProjectSlashCommand {
|
||||||
|
@ -50,6 +51,10 @@ impl SlashCommand for ProjectSlashCommand {
|
||||||
"Generate a semantic search based on context".into()
|
"Generate a semantic search based on context".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::Folder
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ impl SlashCommand for PromptSlashCommand {
|
||||||
"Insert prompt from library".into()
|
"Insert prompt from library".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::Library
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,10 @@ impl SlashCommand for SearchSlashCommand {
|
||||||
"Search your project semantically".into()
|
"Search your project semantically".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::SearchCode
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,10 @@ impl SlashCommand for OutlineSlashCommand {
|
||||||
"Insert symbols for active tab".into()
|
"Insert symbols for active tab".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::ListTree
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{atomic::AtomicBool, Arc},
|
sync::{atomic::AtomicBool, Arc},
|
||||||
};
|
};
|
||||||
use ui::{ActiveTheme, WindowContext};
|
use ui::{prelude::*, ActiveTheme, WindowContext};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
|
@ -31,6 +31,10 @@ impl SlashCommand for TabSlashCommand {
|
||||||
"Insert open tabs (active tab by default)".to_owned()
|
"Insert open tabs (active tab by default)".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::FileTree
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,10 @@ impl SlashCommand for TerminalSlashCommand {
|
||||||
"Insert terminal output".into()
|
"Insert terminal output".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::Terminal
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_text(&self) -> String {
|
fn menu_text(&self) -> String {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,13 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use assistant_slash_command::SlashCommandRegistry;
|
use assistant_slash_command::SlashCommandRegistry;
|
||||||
use gpui::AnyElement;
|
|
||||||
use gpui::DismissEvent;
|
|
||||||
use gpui::WeakView;
|
|
||||||
use picker::PickerEditorPosition;
|
|
||||||
|
|
||||||
use ui::ListItemSpacing;
|
use gpui::{AnyElement, DismissEvent, SharedString, Task, WeakView};
|
||||||
|
use picker::{Picker, PickerDelegate, PickerEditorPosition};
|
||||||
use gpui::SharedString;
|
use ui::{prelude::*, KeyBinding, ListItem, ListItemSpacing, PopoverMenu, PopoverTrigger};
|
||||||
use gpui::Task;
|
|
||||||
use picker::{Picker, PickerDelegate};
|
|
||||||
use ui::{prelude::*, ListItem, PopoverMenu, PopoverTrigger};
|
|
||||||
|
|
||||||
use crate::assistant_panel::ContextEditor;
|
use crate::assistant_panel::ContextEditor;
|
||||||
|
use crate::QuoteSelection;
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub(super) struct SlashCommandSelector<T: PopoverTrigger> {
|
pub(super) struct SlashCommandSelector<T: PopoverTrigger> {
|
||||||
|
@ -27,6 +21,7 @@ struct SlashCommandInfo {
|
||||||
name: SharedString,
|
name: SharedString,
|
||||||
description: SharedString,
|
description: SharedString,
|
||||||
args: Option<SharedString>,
|
args: Option<SharedString>,
|
||||||
|
icon: IconName,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -37,6 +32,7 @@ enum SlashCommandEntry {
|
||||||
renderer: fn(&mut WindowContext<'_>) -> AnyElement,
|
renderer: fn(&mut WindowContext<'_>) -> AnyElement,
|
||||||
on_confirm: fn(&mut WindowContext<'_>),
|
on_confirm: fn(&mut WindowContext<'_>),
|
||||||
},
|
},
|
||||||
|
QuoteButton,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<str> for SlashCommandEntry {
|
impl AsRef<str> for SlashCommandEntry {
|
||||||
|
@ -44,6 +40,7 @@ impl AsRef<str> for SlashCommandEntry {
|
||||||
match self {
|
match self {
|
||||||
SlashCommandEntry::Info(SlashCommandInfo { name, .. })
|
SlashCommandEntry::Info(SlashCommandInfo { name, .. })
|
||||||
| SlashCommandEntry::Advert { name, .. } => name,
|
| SlashCommandEntry::Advert { name, .. } => name,
|
||||||
|
SlashCommandEntry::QuoteButton => "Quote Selection",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,17 +142,24 @@ impl PickerDelegate for SlashCommandDelegate {
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
|
fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
|
||||||
if let Some(command) = self.filtered_commands.get(self.selected_index) {
|
if let Some(command) = self.filtered_commands.get(self.selected_index) {
|
||||||
if let SlashCommandEntry::Info(info) = command {
|
match command {
|
||||||
|
SlashCommandEntry::Info(info) => {
|
||||||
self.active_context_editor
|
self.active_context_editor
|
||||||
.update(cx, |context_editor, cx| {
|
.update(cx, |context_editor, cx| {
|
||||||
context_editor.insert_command(&info.name, cx)
|
context_editor.insert_command(&info.name, cx)
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
} else if let SlashCommandEntry::Advert { on_confirm, .. } = command {
|
}
|
||||||
|
SlashCommandEntry::QuoteButton => {
|
||||||
|
cx.dispatch_action(Box::new(QuoteSelection));
|
||||||
|
}
|
||||||
|
SlashCommandEntry::Advert { on_confirm, .. } => {
|
||||||
on_confirm(cx);
|
on_confirm(cx);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
cx.emit(DismissEvent);
|
cx.emit(DismissEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,18 +185,17 @@ impl PickerDelegate for SlashCommandDelegate {
|
||||||
.spacing(ListItemSpacing::Dense)
|
.spacing(ListItemSpacing::Dense)
|
||||||
.selected(selected)
|
.selected(selected)
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
v_flex()
|
||||||
.group(format!("command-entry-label-{ix}"))
|
.group(format!("command-entry-label-{ix}"))
|
||||||
.w_full()
|
.w_full()
|
||||||
.min_w(px(250.))
|
.min_w(px(250.))
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
.gap_1p5()
|
||||||
|
.child(Icon::new(info.icon).size(IconSize::XSmall))
|
||||||
.child(div().font_buffer(cx).child({
|
.child(div().font_buffer(cx).child({
|
||||||
let mut label = format!("/{}", info.name);
|
let mut label = format!("{}", info.name);
|
||||||
if let Some(args) =
|
if let Some(args) = info.args.as_ref().filter(|_| selected)
|
||||||
info.args.as_ref().filter(|_| selected)
|
|
||||||
{
|
{
|
||||||
label.push_str(&args);
|
label.push_str(&args);
|
||||||
}
|
}
|
||||||
|
@ -220,7 +223,40 @@ impl PickerDelegate for SlashCommandDelegate {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SlashCommandEntry::QuoteButton => {
|
||||||
|
let focus = cx.focus_handle();
|
||||||
|
let key_binding = KeyBinding::for_action_in(&QuoteSelection, &focus, cx);
|
||||||
|
|
||||||
|
Some(
|
||||||
|
ListItem::new(ix)
|
||||||
|
.inset(true)
|
||||||
|
.spacing(ListItemSpacing::Dense)
|
||||||
|
.selected(selected)
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_1p5()
|
||||||
|
.child(Icon::new(IconName::Quote).size(IconSize::XSmall))
|
||||||
|
.child(
|
||||||
|
div().font_buffer(cx).child(
|
||||||
|
Label::new("selection").size(LabelSize::Small),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_1p5()
|
||||||
|
.child(
|
||||||
|
Label::new("Insert editor selection")
|
||||||
|
.color(Color::Muted)
|
||||||
|
.size(LabelSize::Small),
|
||||||
|
)
|
||||||
|
.children(key_binding.map(|kb| kb.render(cx))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
SlashCommandEntry::Advert { renderer, .. } => Some(
|
SlashCommandEntry::Advert { renderer, .. } => Some(
|
||||||
ListItem::new(ix)
|
ListItem::new(ix)
|
||||||
.inset(true)
|
.inset(true)
|
||||||
|
@ -251,31 +287,50 @@ impl<T: PopoverTrigger> RenderOnce for SlashCommandSelector<T> {
|
||||||
name: command_name.into(),
|
name: command_name.into(),
|
||||||
description: menu_text,
|
description: menu_text,
|
||||||
args,
|
args,
|
||||||
|
icon: command.icon(),
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
.chain([SlashCommandEntry::Advert {
|
.chain([
|
||||||
|
SlashCommandEntry::Advert {
|
||||||
name: "create-your-command".into(),
|
name: "create-your-command".into(),
|
||||||
renderer: |cx| {
|
renderer: |cx| {
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.w_full()
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
.w_full()
|
||||||
.font_buffer(cx)
|
.font_buffer(cx)
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap_1()
|
.justify_between()
|
||||||
.child(div().font_buffer(cx).child(
|
.child(
|
||||||
Label::new("create-your-command").size(LabelSize::Small),
|
h_flex()
|
||||||
))
|
.items_center()
|
||||||
.child(Icon::new(IconName::ArrowUpRight).size(IconSize::XSmall)),
|
.gap_1p5()
|
||||||
|
.child(Icon::new(IconName::Plus).size(IconSize::XSmall))
|
||||||
|
.child(
|
||||||
|
div().font_buffer(cx).child(
|
||||||
|
Label::new("create-your-command")
|
||||||
|
.size(LabelSize::Small),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Label::new("Learn how to create a custom command")
|
Icon::new(IconName::ArrowUpRight)
|
||||||
|
.size(IconSize::XSmall)
|
||||||
|
.color(Color::Muted),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Label::new("Create your custom command")
|
||||||
.size(LabelSize::Small)
|
.size(LabelSize::Small)
|
||||||
.color(Color::Muted),
|
.color(Color::Muted),
|
||||||
)
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
},
|
},
|
||||||
on_confirm: |cx| cx.open_url("https://zed.dev/docs/extensions/slash-commands"),
|
on_confirm: |cx| cx.open_url("https://zed.dev/docs/extensions/slash-commands"),
|
||||||
}])
|
},
|
||||||
|
SlashCommandEntry::QuoteButton,
|
||||||
|
])
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let delegate = SlashCommandDelegate {
|
let delegate = SlashCommandDelegate {
|
||||||
|
|
|
@ -62,6 +62,9 @@ pub type SlashCommandResult = Result<BoxStream<'static, Result<SlashCommandEvent
|
||||||
|
|
||||||
pub trait SlashCommand: 'static + Send + Sync {
|
pub trait SlashCommand: 'static + Send + Sync {
|
||||||
fn name(&self) -> String;
|
fn name(&self) -> String;
|
||||||
|
fn icon(&self) -> IconName {
|
||||||
|
IconName::Slash
|
||||||
|
}
|
||||||
fn label(&self, _cx: &AppContext) -> CodeLabel {
|
fn label(&self, _cx: &AppContext) -> CodeLabel {
|
||||||
CodeLabel::plain(self.name(), None)
|
CodeLabel::plain(self.name(), None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,6 +284,7 @@ pub enum IconName {
|
||||||
Update,
|
Update,
|
||||||
UserGroup,
|
UserGroup,
|
||||||
Visible,
|
Visible,
|
||||||
|
Wand,
|
||||||
Warning,
|
Warning,
|
||||||
WholeWord,
|
WholeWord,
|
||||||
XCircle,
|
XCircle,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue