Autocomplete commands that don't require access to workspace in prompt library (#12674)
This is useful to autocomplete prompts when writing a new one in the prompt library. Release Notes: - N/A
This commit is contained in:
parent
ad2ddf1200
commit
27e9c68988
14 changed files with 88 additions and 196 deletions
|
@ -2580,9 +2580,9 @@ impl ConversationEditor {
|
||||||
let slash_command_registry = conversation.read(cx).slash_command_registry.clone();
|
let slash_command_registry = conversation.read(cx).slash_command_registry.clone();
|
||||||
|
|
||||||
let completion_provider = SlashCommandCompletionProvider::new(
|
let completion_provider = SlashCommandCompletionProvider::new(
|
||||||
cx.view().downgrade(),
|
|
||||||
slash_command_registry.clone(),
|
slash_command_registry.clone(),
|
||||||
workspace.downgrade(),
|
Some(cx.view().downgrade()),
|
||||||
|
Some(workspace.downgrade()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let editor = cx.new_view(|cx| {
|
let editor = cx.new_view(|cx| {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
slash_command::SlashCommandLine, CompletionProvider, LanguageModelRequest,
|
slash_command::SlashCommandCompletionProvider, CompletionProvider, LanguageModelRequest,
|
||||||
LanguageModelRequestMessage, Role,
|
LanguageModelRequestMessage, Role,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
@ -11,17 +11,14 @@ use futures::{
|
||||||
future::{self, BoxFuture, Shared},
|
future::{self, BoxFuture, Shared},
|
||||||
FutureExt,
|
FutureExt,
|
||||||
};
|
};
|
||||||
use fuzzy::{match_strings, StringMatchCandidate};
|
use fuzzy::StringMatchCandidate;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, point, size, AnyElement, AppContext, BackgroundExecutor, Bounds, DevicePixels,
|
actions, point, size, AnyElement, AppContext, BackgroundExecutor, Bounds, DevicePixels,
|
||||||
EventEmitter, Global, Model, PromptLevel, ReadGlobal, Subscription, Task, TitlebarOptions,
|
EventEmitter, Global, PromptLevel, ReadGlobal, Subscription, Task, TitlebarOptions, View,
|
||||||
View, WindowBounds, WindowHandle, WindowOptions,
|
WindowBounds, WindowHandle, WindowOptions,
|
||||||
};
|
};
|
||||||
use heed::{types::SerdeBincode, Database, RoTxn};
|
use heed::{types::SerdeBincode, Database, RoTxn};
|
||||||
use language::{
|
use language::{language_settings::SoftWrap, Buffer, LanguageRegistry};
|
||||||
language_settings::SoftWrap, Buffer, Documentation, LanguageRegistry, LanguageServerId, Point,
|
|
||||||
ToPoint as _,
|
|
||||||
};
|
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use picker::{Picker, PickerDelegate};
|
use picker::{Picker, PickerDelegate};
|
||||||
use rope::Rope;
|
use rope::Rope;
|
||||||
|
@ -482,6 +479,7 @@ impl PromptLibrary {
|
||||||
self.set_active_prompt(Some(prompt_id), cx);
|
self.set_active_prompt(Some(prompt_id), cx);
|
||||||
} else {
|
} else {
|
||||||
let language_registry = self.language_registry.clone();
|
let language_registry = self.language_registry.clone();
|
||||||
|
let commands = SlashCommandRegistry::global(cx);
|
||||||
let prompt = self.store.load(prompt_id);
|
let prompt = self.store.load(prompt_id);
|
||||||
self.pending_load = cx.spawn(|this, mut cx| async move {
|
self.pending_load = cx.spawn(|this, mut cx| async move {
|
||||||
let prompt = prompt.await;
|
let prompt = prompt.await;
|
||||||
|
@ -500,8 +498,9 @@ impl PromptLibrary {
|
||||||
editor.set_show_gutter(false, cx);
|
editor.set_show_gutter(false, cx);
|
||||||
editor.set_show_wrap_guides(false, cx);
|
editor.set_show_wrap_guides(false, cx);
|
||||||
editor.set_show_indent_guides(false, cx);
|
editor.set_show_indent_guides(false, cx);
|
||||||
editor
|
editor.set_completion_provider(Box::new(
|
||||||
.set_completion_provider(Box::new(SlashCommandCompletionProvider));
|
SlashCommandCompletionProvider::new(commands, None, None),
|
||||||
|
));
|
||||||
if focus {
|
if focus {
|
||||||
editor.focus(cx);
|
editor.focus(cx);
|
||||||
}
|
}
|
||||||
|
@ -1092,123 +1091,3 @@ fn title_from_body(body: impl IntoIterator<Item = char>) -> Option<SharedString>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SlashCommandCompletionProvider;
|
|
||||||
|
|
||||||
impl editor::CompletionProvider for SlashCommandCompletionProvider {
|
|
||||||
fn completions(
|
|
||||||
&self,
|
|
||||||
buffer: &Model<Buffer>,
|
|
||||||
buffer_position: language::Anchor,
|
|
||||||
cx: &mut ViewContext<Editor>,
|
|
||||||
) -> Task<Result<Vec<project::Completion>>> {
|
|
||||||
let Some((command_name, name_range)) = buffer.update(cx, |buffer, _cx| {
|
|
||||||
let position = buffer_position.to_point(buffer);
|
|
||||||
let line_start = Point::new(position.row, 0);
|
|
||||||
let mut lines = buffer.text_for_range(line_start..position).lines();
|
|
||||||
let line = lines.next()?;
|
|
||||||
let call = SlashCommandLine::parse(line)?;
|
|
||||||
|
|
||||||
if call.argument.is_some() {
|
|
||||||
// Don't autocomplete arguments.
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let name = line[call.name.clone()].to_string();
|
|
||||||
let name_range_start = Point::new(position.row, call.name.start as u32);
|
|
||||||
let name_range_end = Point::new(position.row, call.name.end as u32);
|
|
||||||
let name_range =
|
|
||||||
buffer.anchor_after(name_range_start)..buffer.anchor_after(name_range_end);
|
|
||||||
Some((name, name_range))
|
|
||||||
}
|
|
||||||
}) else {
|
|
||||||
return Task::ready(Ok(Vec::new()));
|
|
||||||
};
|
|
||||||
|
|
||||||
let commands = SlashCommandRegistry::global(cx);
|
|
||||||
let candidates = commands
|
|
||||||
.command_names()
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(ix, def)| StringMatchCandidate {
|
|
||||||
id: ix,
|
|
||||||
string: def.to_string(),
|
|
||||||
char_bag: def.as_ref().into(),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let command_name = command_name.to_string();
|
|
||||||
cx.spawn(|_, mut cx| async move {
|
|
||||||
let matches = match_strings(
|
|
||||||
&candidates,
|
|
||||||
&command_name,
|
|
||||||
true,
|
|
||||||
usize::MAX,
|
|
||||||
&Default::default(),
|
|
||||||
cx.background_executor().clone(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
cx.update(|cx| {
|
|
||||||
matches
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|mat| {
|
|
||||||
let command = commands.command(&mat.string)?;
|
|
||||||
let mut new_text = mat.string.clone();
|
|
||||||
let requires_argument = command.requires_argument();
|
|
||||||
if requires_argument {
|
|
||||||
new_text.push(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(project::Completion {
|
|
||||||
old_range: name_range.clone(),
|
|
||||||
documentation: Some(Documentation::SingleLine(command.description())),
|
|
||||||
new_text,
|
|
||||||
label: command.label(cx),
|
|
||||||
server_id: LanguageServerId(0),
|
|
||||||
lsp_completion: Default::default(),
|
|
||||||
show_new_completions_on_confirm: false,
|
|
||||||
confirm: None,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_completions(
|
|
||||||
&self,
|
|
||||||
_: Model<Buffer>,
|
|
||||||
_: Vec<usize>,
|
|
||||||
_: Arc<RwLock<Box<[project::Completion]>>>,
|
|
||||||
_: &mut ViewContext<Editor>,
|
|
||||||
) -> Task<Result<bool>> {
|
|
||||||
Task::ready(Ok(true))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_additional_edits_for_completion(
|
|
||||||
&self,
|
|
||||||
_: Model<Buffer>,
|
|
||||||
_: project::Completion,
|
|
||||||
_: bool,
|
|
||||||
_: &mut ViewContext<Editor>,
|
|
||||||
) -> Task<Result<Option<language::Transaction>>> {
|
|
||||||
Task::ready(Ok(None))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_completion_trigger(
|
|
||||||
&self,
|
|
||||||
buffer: &Model<Buffer>,
|
|
||||||
position: language::Anchor,
|
|
||||||
_text: &str,
|
|
||||||
_trigger_in_words: bool,
|
|
||||||
cx: &mut ViewContext<Editor>,
|
|
||||||
) -> bool {
|
|
||||||
let buffer = buffer.read(cx);
|
|
||||||
let position = position.to_point(buffer);
|
|
||||||
let line_start = Point::new(position.row, 0);
|
|
||||||
let mut lines = buffer.text_for_range(line_start..position).lines();
|
|
||||||
if let Some(line) = lines.next() {
|
|
||||||
SlashCommandLine::parse(line).is_some()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -27,10 +27,10 @@ pub mod search_command;
|
||||||
pub mod tabs_command;
|
pub mod tabs_command;
|
||||||
|
|
||||||
pub(crate) struct SlashCommandCompletionProvider {
|
pub(crate) struct SlashCommandCompletionProvider {
|
||||||
editor: WeakView<ConversationEditor>,
|
|
||||||
commands: Arc<SlashCommandRegistry>,
|
commands: Arc<SlashCommandRegistry>,
|
||||||
cancel_flag: Mutex<Arc<AtomicBool>>,
|
cancel_flag: Mutex<Arc<AtomicBool>>,
|
||||||
workspace: WeakView<Workspace>,
|
editor: Option<WeakView<ConversationEditor>>,
|
||||||
|
workspace: Option<WeakView<Workspace>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct SlashCommandLine {
|
pub(crate) struct SlashCommandLine {
|
||||||
|
@ -42,9 +42,9 @@ pub(crate) struct SlashCommandLine {
|
||||||
|
|
||||||
impl SlashCommandCompletionProvider {
|
impl SlashCommandCompletionProvider {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
editor: WeakView<ConversationEditor>,
|
|
||||||
commands: Arc<SlashCommandRegistry>,
|
commands: Arc<SlashCommandRegistry>,
|
||||||
workspace: WeakView<Workspace>,
|
editor: Option<WeakView<ConversationEditor>>,
|
||||||
|
workspace: Option<WeakView<Workspace>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cancel_flag: Mutex::new(Arc::new(AtomicBool::new(false))),
|
cancel_flag: Mutex::new(Arc::new(AtomicBool::new(false))),
|
||||||
|
@ -98,6 +98,30 @@ impl SlashCommandCompletionProvider {
|
||||||
new_text.push(' ');
|
new_text.push(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let confirm = editor.clone().zip(workspace.clone()).and_then(
|
||||||
|
|(editor, workspace)| {
|
||||||
|
(!requires_argument).then(|| {
|
||||||
|
let command_name = mat.string.clone();
|
||||||
|
let command_range = command_range.clone();
|
||||||
|
let editor = editor.clone();
|
||||||
|
let workspace = workspace.clone();
|
||||||
|
Arc::new(move |cx: &mut WindowContext| {
|
||||||
|
editor
|
||||||
|
.update(cx, |editor, cx| {
|
||||||
|
editor.run_command(
|
||||||
|
command_range.clone(),
|
||||||
|
&command_name,
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
workspace.clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}) as Arc<_>
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
Some(project::Completion {
|
Some(project::Completion {
|
||||||
old_range: name_range.clone(),
|
old_range: name_range.clone(),
|
||||||
documentation: Some(Documentation::SingleLine(command.description())),
|
documentation: Some(Documentation::SingleLine(command.description())),
|
||||||
|
@ -106,26 +130,7 @@ impl SlashCommandCompletionProvider {
|
||||||
server_id: LanguageServerId(0),
|
server_id: LanguageServerId(0),
|
||||||
lsp_completion: Default::default(),
|
lsp_completion: Default::default(),
|
||||||
show_new_completions_on_confirm: requires_argument,
|
show_new_completions_on_confirm: requires_argument,
|
||||||
confirm: (!requires_argument).then(|| {
|
confirm,
|
||||||
let command_name = mat.string.clone();
|
|
||||||
let command_range = command_range.clone();
|
|
||||||
let editor = editor.clone();
|
|
||||||
let workspace = workspace.clone();
|
|
||||||
Arc::new(move |cx: &mut WindowContext| {
|
|
||||||
editor
|
|
||||||
.update(cx, |editor, cx| {
|
|
||||||
editor.run_command(
|
|
||||||
command_range.clone(),
|
|
||||||
&command_name,
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
workspace.clone(),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}) as Arc<_>
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -160,34 +165,42 @@ impl SlashCommandCompletionProvider {
|
||||||
Ok(completions
|
Ok(completions
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|arg| project::Completion {
|
.map(|command_argument| {
|
||||||
old_range: argument_range.clone(),
|
let confirm =
|
||||||
label: CodeLabel::plain(arg.clone(), None),
|
editor
|
||||||
new_text: arg.clone(),
|
.clone()
|
||||||
documentation: None,
|
.zip(workspace.clone())
|
||||||
server_id: LanguageServerId(0),
|
.map(|(editor, workspace)| {
|
||||||
lsp_completion: Default::default(),
|
Arc::new({
|
||||||
show_new_completions_on_confirm: false,
|
let command_range = command_range.clone();
|
||||||
confirm: Some(Arc::new({
|
let command_name = command_name.clone();
|
||||||
let command_name = command_name.clone();
|
let command_argument = command_argument.clone();
|
||||||
let command_range = command_range.clone();
|
move |cx: &mut WindowContext| {
|
||||||
let editor = editor.clone();
|
editor
|
||||||
let workspace = workspace.clone();
|
.update(cx, |editor, cx| {
|
||||||
move |cx| {
|
editor.run_command(
|
||||||
editor
|
command_range.clone(),
|
||||||
.update(cx, |editor, cx| {
|
&command_name,
|
||||||
editor.run_command(
|
Some(&command_argument),
|
||||||
command_range.clone(),
|
true,
|
||||||
&command_name,
|
workspace.clone(),
|
||||||
Some(&arg),
|
cx,
|
||||||
true,
|
);
|
||||||
workspace.clone(),
|
})
|
||||||
cx,
|
.ok();
|
||||||
);
|
}
|
||||||
})
|
}) as Arc<_>
|
||||||
.ok();
|
});
|
||||||
}
|
project::Completion {
|
||||||
})),
|
old_range: argument_range.clone(),
|
||||||
|
label: CodeLabel::plain(command_argument.clone(), None),
|
||||||
|
new_text: command_argument.clone(),
|
||||||
|
documentation: None,
|
||||||
|
server_id: LanguageServerId(0),
|
||||||
|
lsp_completion: Default::default(),
|
||||||
|
show_new_completions_on_confirm: false,
|
||||||
|
confirm,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
})
|
})
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl SlashCommand for ActiveSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
_query: String,
|
_query: String,
|
||||||
_cancel: std::sync::Arc<std::sync::atomic::AtomicBool>,
|
_cancel: std::sync::Arc<std::sync::atomic::AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
Task::ready(Err(anyhow!("this command does not require argument")))
|
Task::ready(Err(anyhow!("this command does not require argument")))
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl SlashCommand for DefaultSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
_query: String,
|
_query: String,
|
||||||
_cancellation_flag: Arc<AtomicBool>,
|
_cancellation_flag: Arc<AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
Task::ready(Err(anyhow!("this command does not require argument")))
|
Task::ready(Err(anyhow!("this command does not require argument")))
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl SlashCommand for FetchSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
_query: String,
|
_query: String,
|
||||||
_cancel: Arc<AtomicBool>,
|
_cancel: Arc<AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
Task::ready(Ok(Vec::new()))
|
Task::ready(Ok(Vec::new()))
|
||||||
|
|
|
@ -101,10 +101,10 @@ impl SlashCommand for FileSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
query: String,
|
query: String,
|
||||||
cancellation_flag: Arc<AtomicBool>,
|
cancellation_flag: Arc<AtomicBool>,
|
||||||
workspace: WeakView<Workspace>,
|
workspace: Option<WeakView<Workspace>>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
let Some(workspace) = workspace.upgrade() else {
|
let Some(workspace) = workspace.and_then(|workspace| workspace.upgrade()) else {
|
||||||
return Task::ready(Err(anyhow!("workspace was dropped")));
|
return Task::ready(Err(anyhow!("workspace was dropped")));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ impl SlashCommand for ProjectSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
_query: String,
|
_query: String,
|
||||||
_cancel: Arc<AtomicBool>,
|
_cancel: Arc<AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
Task::ready(Err(anyhow!("this command does not require argument")))
|
Task::ready(Err(anyhow!("this command does not require argument")))
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl SlashCommand for PromptSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
query: String,
|
query: String,
|
||||||
_cancellation_flag: Arc<AtomicBool>,
|
_cancellation_flag: Arc<AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
let store = PromptStore::global(cx);
|
let store = PromptStore::global(cx);
|
||||||
|
|
|
@ -119,7 +119,7 @@ impl SlashCommand for RustdocSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
_query: String,
|
_query: String,
|
||||||
_cancel: Arc<AtomicBool>,
|
_cancel: Arc<AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
Task::ready(Ok(Vec::new()))
|
Task::ready(Ok(Vec::new()))
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl SlashCommand for SearchSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
_query: String,
|
_query: String,
|
||||||
_cancel: Arc<AtomicBool>,
|
_cancel: Arc<AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
Task::ready(Ok(Vec::new()))
|
Task::ready(Ok(Vec::new()))
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl SlashCommand for TabsSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
_query: String,
|
_query: String,
|
||||||
_cancel: Arc<std::sync::atomic::AtomicBool>,
|
_cancel: Arc<std::sync::atomic::AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
Task::ready(Err(anyhow!("this command does not require argument")))
|
Task::ready(Err(anyhow!("this command does not require argument")))
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub trait SlashCommand: 'static + Send + Sync {
|
||||||
&self,
|
&self,
|
||||||
query: String,
|
query: String,
|
||||||
cancel: Arc<AtomicBool>,
|
cancel: Arc<AtomicBool>,
|
||||||
workspace: WeakView<Workspace>,
|
workspace: Option<WeakView<Workspace>>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>>;
|
) -> Task<Result<Vec<String>>>;
|
||||||
fn requires_argument(&self) -> bool;
|
fn requires_argument(&self) -> bool;
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl SlashCommand for ExtensionSlashCommand {
|
||||||
&self,
|
&self,
|
||||||
_query: String,
|
_query: String,
|
||||||
_cancel: Arc<AtomicBool>,
|
_cancel: Arc<AtomicBool>,
|
||||||
_workspace: WeakView<Workspace>,
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Task<Result<Vec<String>>> {
|
) -> Task<Result<Vec<String>>> {
|
||||||
Task::ready(Ok(Vec::new()))
|
Task::ready(Ok(Vec::new()))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue