Detailed changes
@@ -73,57 +73,58 @@ impl SlashCommandCompletionProvider {
let command_name = command_name.to_string();
let editor = self.editor.clone();
let workspace = self.workspace.clone();
- let executor = cx.background_executor().clone();
- executor.clone().spawn(async move {
+ cx.spawn(|mut cx| async move {
let matches = match_strings(
&candidates,
&command_name,
true,
usize::MAX,
&Default::default(),
- executor,
+ cx.background_executor().clone(),
)
.await;
- Ok(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(' ');
- }
+ 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: CodeLabel::plain(mat.string.clone(), None),
- server_id: LanguageServerId(0),
- lsp_completion: Default::default(),
- confirm: (!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,
- workspace.clone(),
- cx,
- );
- })
- .ok();
- }) as Arc<_>
- }),
+ 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(),
+ confirm: (!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,
+ workspace.clone(),
+ cx,
+ );
+ })
+ .ok();
+ }) as Arc<_>
+ }),
+ })
})
- })
- .collect())
+ .collect()
+ })
})
}
@@ -2,7 +2,7 @@ use super::{file_command::FilePlaceholder, SlashCommand, SlashCommandOutput};
use anyhow::Result;
use assistant_slash_command::SlashCommandOutputSection;
use gpui::{AppContext, Task, WeakView};
-use language::{LineEnding, LspAdapterDelegate};
+use language::{CodeLabel, HighlightId, LineEnding, LspAdapterDelegate};
use semantic_index::SemanticIndex;
use std::{
fmt::Write,
@@ -20,6 +20,17 @@ impl SlashCommand for SearchSlashCommand {
"search".into()
}
+ fn label(&self, cx: &AppContext) -> CodeLabel {
+ let mut label = CodeLabel::default();
+ label.push_str("search ", None);
+ label.push_str(
+ "--n",
+ cx.theme().syntax().highlight_id("comment").map(HighlightId),
+ );
+ label.filter_range = 0.."search".len();
+ label
+ }
+
fn description(&self) -> String {
"semantically search files".into()
}
@@ -54,12 +65,27 @@ impl SlashCommand for SearchSlashCommand {
let Some(argument) = argument else {
return Task::ready(Err(anyhow::anyhow!("missing search query")));
};
- if argument.is_empty() {
+
+ let mut limit = None;
+ let mut query = String::new();
+ for part in argument.split(' ') {
+ if let Some(parameter) = part.strip_prefix("--") {
+ if let Ok(count) = parameter.parse::<usize>() {
+ limit = Some(count);
+ continue;
+ }
+ }
+
+ query.push_str(part);
+ query.push(' ');
+ }
+ query.pop();
+
+ if query.is_empty() {
return Task::ready(Err(anyhow::anyhow!("missing search query")));
}
let project = workspace.read(cx).project().clone();
- let argument = argument.to_string();
let fs = project.read(cx).fs().clone();
let project_index =
cx.update_global(|index: &mut SemanticIndex, cx| index.project_index(project, cx));
@@ -67,7 +93,7 @@ impl SlashCommand for SearchSlashCommand {
cx.spawn(|cx| async move {
let results = project_index
.read_with(&cx, |project_index, cx| {
- project_index.search(argument.clone(), 5, cx)
+ project_index.search(query.clone(), limit.unwrap_or(5), cx)
})?
.await?;
@@ -92,7 +118,7 @@ impl SlashCommand for SearchSlashCommand {
let output = cx
.background_executor()
.spawn(async move {
- let mut text = format!("Search results for {argument}:\n");
+ let mut text = format!("Search results for {query}:\n");
let mut sections = Vec::new();
for (result, full_path, file_content) in loaded_results {
let range_start = result.range.start.min(file_content.len());
@@ -140,7 +166,7 @@ impl SlashCommand for SearchSlashCommand {
});
}
- let argument = SharedString::from(argument);
+ let query = SharedString::from(query);
sections.push(SlashCommandOutputSection {
range: 0..text.len(),
render_placeholder: Arc::new(move |id, unfold, _cx| {
@@ -148,7 +174,7 @@ impl SlashCommand for SearchSlashCommand {
.style(ButtonStyle::Filled)
.layer(ElevationIndex::ElevatedSurface)
.child(Icon::new(IconName::MagnifyingGlass))
- .child(Label::new(argument.clone()))
+ .child(Label::new(query.clone()))
.on_click(move |_, cx| unfold(cx))
.into_any_element()
}),
@@ -2,7 +2,7 @@ mod slash_command_registry;
use anyhow::Result;
use gpui::{AnyElement, AppContext, ElementId, Task, WeakView, WindowContext};
-use language::LspAdapterDelegate;
+use language::{CodeLabel, LspAdapterDelegate};
pub use slash_command_registry::*;
use std::{
ops::Range,
@@ -16,6 +16,9 @@ pub fn init(cx: &mut AppContext) {
pub trait SlashCommand: 'static + Send + Sync {
fn name(&self) -> String;
+ fn label(&self, _cx: &AppContext) -> CodeLabel {
+ CodeLabel::plain(self.name(), None)
+ }
fn description(&self) -> String;
fn tooltip_text(&self) -> String;
fn complete_argument(
@@ -535,7 +535,7 @@ async fn try_fetch_server_binary<L: LspAdapter + 'static + Send + Sync + ?Sized>
binary
}
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct CodeLabel {
/// The text to display.
pub text: String,
@@ -1540,6 +1540,15 @@ impl CodeLabel {
}
result
}
+
+ pub fn push_str(&mut self, text: &str, highlight: Option<HighlightId>) {
+ let start_ix = self.text.len();
+ self.text.push_str(text);
+ let end_ix = self.text.len();
+ if let Some(highlight) = highlight {
+ self.runs.push((start_ix..end_ix, highlight));
+ }
+ }
}
impl Ord for LanguageMatcher {
@@ -44,6 +44,11 @@ impl SyntaxTheme {
self.get(name).color.unwrap_or_default()
}
+ pub fn highlight_id(&self, name: &str) -> Option<u32> {
+ let ix = self.highlights.iter().position(|entry| entry.0 == name)?;
+ Some(ix as u32)
+ }
+
/// Returns a new [`Arc<SyntaxTheme>`] with the given syntax styles merged in.
pub fn merge(base: Arc<Self>, user_syntax_styles: Vec<(String, HighlightStyle)>) -> Arc<Self> {
if user_syntax_styles.is_empty() {