mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Allow specifying a custom limit for /search results (#12423)
<img width="497" alt="image" src="https://github.com/zed-industries/zed/assets/482957/94e94326-fb3c-4f9b-b4d9-7dd6f6f8d537"> e.g. ``` /search --9 foobar ``` Release Notes: - N/A
This commit is contained in:
parent
f3e6a0beab
commit
a0644ac601
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user