Detailed changes
@@ -863,7 +863,6 @@ dependencies = [
"assistant_slash_command",
"chrono",
"collections",
- "context_server",
"editor",
"feature_flags",
"fs",
@@ -2346,7 +2345,6 @@ dependencies = [
name = "breadcrumbs"
version = "0.1.0"
dependencies = [
- "editor",
"gpui",
"ui",
"workspace",
@@ -4975,7 +4973,6 @@ dependencies = [
"pretty_assertions",
"project",
"rand 0.9.2",
- "search",
"serde",
"serde_json",
"settings",
@@ -5506,6 +5503,7 @@ dependencies = [
"aho-corasick",
"anyhow",
"assets",
+ "breadcrumbs",
"buffer_diff",
"client",
"clock",
@@ -14859,7 +14857,6 @@ dependencies = [
"menu",
"pretty_assertions",
"project",
- "schemars",
"serde",
"serde_json",
"settings",
@@ -16887,7 +16884,6 @@ dependencies = [
"rand 0.9.2",
"regex",
"schemars",
- "search",
"serde",
"serde_json",
"settings",
@@ -21260,6 +21256,7 @@ dependencies = [
"gpui",
"schemars",
"serde",
+ "util",
"uuid",
]
@@ -16,7 +16,6 @@ anyhow.workspace = true
assistant_slash_command.workspace = true
chrono.workspace = true
collections.workspace = true
-context_server.workspace = true
editor.workspace = true
feature_flags.workspace = true
fs.workspace = true
@@ -1,4 +1,3 @@
-mod context_server_command;
mod default_command;
mod delta_command;
mod diagnostics_command;
@@ -11,7 +10,6 @@ mod streaming_example_command;
mod symbols_command;
mod tab_command;
-pub use crate::context_server_command::*;
pub use crate::default_command::*;
pub use crate::delta_command::*;
pub use crate::diagnostics_command::*;
@@ -1,159 +0,0 @@
-use anyhow::{Context as _, Result, anyhow};
-use assistant_slash_command::{
- ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection,
- SlashCommandResult,
-};
-use fs::Fs;
-use gpui::{App, Entity, Task, WeakEntity};
-use language::{BufferSnapshot, LspAdapterDelegate};
-use project::{Project, ProjectPath};
-use std::{
- fmt::Write,
- path::Path,
- sync::{Arc, atomic::AtomicBool},
-};
-use ui::prelude::*;
-use util::rel_path::RelPath;
-use workspace::Workspace;
-
-pub struct CargoWorkspaceSlashCommand;
-
-impl CargoWorkspaceSlashCommand {
- async fn build_message(fs: Arc<dyn Fs>, path_to_cargo_toml: &Path) -> Result<String> {
- let buffer = fs.load(path_to_cargo_toml).await?;
- let cargo_toml: cargo_toml::Manifest = toml::from_str(&buffer)?;
-
- let mut message = String::new();
- writeln!(message, "You are in a Rust project.")?;
-
- if let Some(workspace) = cargo_toml.workspace {
- writeln!(
- message,
- "The project is a Cargo workspace with the following members:"
- )?;
- for member in workspace.members {
- writeln!(message, "- {member}")?;
- }
-
- if !workspace.default_members.is_empty() {
- writeln!(message, "The default members are:")?;
- for member in workspace.default_members {
- writeln!(message, "- {member}")?;
- }
- }
-
- if !workspace.dependencies.is_empty() {
- writeln!(
- message,
- "The following workspace dependencies are installed:"
- )?;
- for dependency in workspace.dependencies.keys() {
- writeln!(message, "- {dependency}")?;
- }
- }
- } else if let Some(package) = cargo_toml.package {
- writeln!(
- message,
- "The project name is \"{name}\".",
- name = package.name
- )?;
-
- let description = package
- .description
- .as_ref()
- .and_then(|description| description.get().ok().cloned());
- if let Some(description) = description.as_ref() {
- writeln!(message, "It describes itself as \"{description}\".")?;
- }
-
- if !cargo_toml.dependencies.is_empty() {
- writeln!(message, "The following dependencies are installed:")?;
- for dependency in cargo_toml.dependencies.keys() {
- writeln!(message, "- {dependency}")?;
- }
- }
- }
-
- Ok(message)
- }
-
- fn path_to_cargo_toml(project: Entity<Project>, cx: &mut App) -> Option<Arc<Path>> {
- let worktree = project.read(cx).worktrees(cx).next()?;
- let worktree = worktree.read(cx);
- let entry = worktree.entry_for_path(RelPath::new("Cargo.toml").unwrap())?;
- let path = ProjectPath {
- worktree_id: worktree.id(),
- path: entry.path.clone(),
- };
- Some(Arc::from(
- project.read(cx).absolute_path(&path, cx)?.as_path(),
- ))
- }
-}
-
-impl SlashCommand for CargoWorkspaceSlashCommand {
- fn name(&self) -> String {
- "cargo-workspace".into()
- }
-
- fn description(&self) -> String {
- "insert project workspace metadata".into()
- }
-
- fn menu_text(&self) -> String {
- "Insert Project Workspace Metadata".into()
- }
-
- fn complete_argument(
- self: Arc<Self>,
- _arguments: &[String],
- _cancel: Arc<AtomicBool>,
- _workspace: Option<WeakEntity<Workspace>>,
- _window: &mut Window,
- _cx: &mut App,
- ) -> Task<Result<Vec<ArgumentCompletion>>> {
- Task::ready(Err(anyhow!("this command does not require argument")))
- }
-
- fn requires_argument(&self) -> bool {
- false
- }
-
- fn run(
- self: Arc<Self>,
- _arguments: &[String],
- _context_slash_command_output_sections: &[SlashCommandOutputSection<language::Anchor>],
- _context_buffer: BufferSnapshot,
- workspace: WeakEntity<Workspace>,
- _delegate: Option<Arc<dyn LspAdapterDelegate>>,
- _window: &mut Window,
- cx: &mut App,
- ) -> Task<SlashCommandResult> {
- let output = workspace.update(cx, |workspace, cx| {
- let project = workspace.project().clone();
- let fs = workspace.project().read(cx).fs().clone();
- let path = Self::path_to_cargo_toml(project, cx);
- let output = cx.background_spawn(async move {
- let path = path.with_context(|| "Cargo.toml not found")?;
- Self::build_message(fs, &path).await
- });
-
- cx.foreground_executor().spawn(async move {
- let text = output.await?;
- let range = 0..text.len();
- Ok(SlashCommandOutput {
- text,
- sections: vec![SlashCommandOutputSection {
- range,
- icon: IconName::FileTree,
- label: "Project".into(),
- metadata: None,
- }],
- run_commands_in_text: false,
- }
- .into_event_stream())
- })
- });
- output.unwrap_or_else(|error| Task::ready(Err(error)))
- }
-}
@@ -18,7 +18,6 @@ test-support = []
agent_settings.workspace = true
anyhow.workspace = true
assistant_slash_command.workspace = true
-assistant_slash_commands.workspace = true
chrono.workspace = true
client.workspace = true
clock.workspace = true
@@ -55,6 +54,7 @@ workspace.workspace = true
zed_env_vars.workspace = true
[dev-dependencies]
+assistant_slash_commands.workspace = true
indoc.workspace = true
language_model = { workspace = true, features = ["test-support"] }
pretty_assertions.workspace = true
@@ -1,5 +1,6 @@
#[cfg(test)]
mod assistant_text_thread_tests;
+mod context_server_command;
mod text_thread;
mod text_thread_store;
@@ -14,7 +14,7 @@ use text::LineEnding;
use ui::{IconName, SharedString};
use workspace::Workspace;
-use crate::create_label_for_command;
+use assistant_slash_command::create_label_for_command;
pub struct ContextServerSlashCommand {
store: Entity<ContextServerStore>,
@@ -4,7 +4,6 @@ use assistant_slash_command::{
SlashCommandContent, SlashCommandEvent, SlashCommandLine, SlashCommandOutputSection,
SlashCommandResult, SlashCommandWorkingSet,
};
-use assistant_slash_commands::FileCommandMetadata;
use client::{self, proto};
use clock::ReplicaId;
use cloud_llm_client::CompletionIntent;
@@ -1176,6 +1175,11 @@ impl TextThread {
}
pub fn contains_files(&self, cx: &App) -> bool {
+ // Mimics assistant_slash_commands::FileCommandMetadata.
+ #[derive(Serialize, Deserialize)]
+ pub struct FileCommandMetadata {
+ pub path: String,
+ }
let buffer = self.buffer.read(cx);
self.slash_command_output_sections.iter().any(|section| {
section.is_valid(buffer)
@@ -1,6 +1,6 @@
use crate::{
SavedTextThread, SavedTextThreadMetadata, TextThread, TextThreadEvent, TextThreadId,
- TextThreadOperation, TextThreadVersion,
+ TextThreadOperation, TextThreadVersion, context_server_command,
};
use anyhow::{Context as _, Result};
use assistant_slash_command::{SlashCommandId, SlashCommandWorkingSet};
@@ -938,11 +938,11 @@ impl TextThreadStore {
let slash_command_ids = response
.prompts
.into_iter()
- .filter(assistant_slash_commands::acceptable_prompt)
+ .filter(context_server_command::acceptable_prompt)
.map(|prompt| {
log::info!("registering context server command: {:?}", prompt.name);
slash_command_working_set.insert(Arc::new(
- assistant_slash_commands::ContextServerSlashCommand::new(
+ context_server_command::ContextServerSlashCommand::new(
context_server_store.clone(),
server.id(),
prompt,
@@ -13,12 +13,10 @@ path = "src/breadcrumbs.rs"
doctest = false
[dependencies]
-editor.workspace = true
gpui.workspace = true
ui.workspace = true
workspace.workspace = true
[dev-dependencies]
-editor = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, features = ["test-support"] }
-workspace = { workspace = true, features = ["test-support"] }
+workspace = { workspace = true, features = ["test-support"] }
@@ -1,11 +1,25 @@
-use editor::render_breadcrumb_text;
-use gpui::{Context, EventEmitter, IntoElement, Render, Subscription, Window};
+use gpui::{
+ AnyElement, App, Context, EventEmitter, Global, IntoElement, Render, Subscription, Window,
+};
use ui::prelude::*;
use workspace::{
ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView,
- item::{ItemEvent, ItemHandle},
+ item::{BreadcrumbText, ItemEvent, ItemHandle},
};
+type RenderBreadcrumbTextFn = fn(
+ Vec<BreadcrumbText>,
+ Option<AnyElement>,
+ &dyn ItemHandle,
+ bool,
+ &mut Window,
+ &App,
+) -> AnyElement;
+
+pub struct RenderBreadcrumbText(pub RenderBreadcrumbTextFn);
+
+impl Global for RenderBreadcrumbText {}
+
pub struct Breadcrumbs {
pane_focused: bool,
active_item: Option<Box<dyn ItemHandle>>,
@@ -49,15 +63,18 @@ impl Render for Breadcrumbs {
let prefix_element = active_item.breadcrumb_prefix(window, cx);
- render_breadcrumb_text(
- segments,
- prefix_element,
- active_item.as_ref(),
- false,
- window,
- cx,
- )
- .into_any_element()
+ if let Some(render_fn) = cx.try_global::<RenderBreadcrumbText>() {
+ (render_fn.0)(
+ segments,
+ prefix_element,
+ active_item.as_ref(),
+ false,
+ window,
+ cx,
+ )
+ } else {
+ element.into_any_element()
+ }
}
}
@@ -27,7 +27,7 @@ lsp.workspace = true
markdown.workspace = true
project.workspace = true
rand.workspace = true
-search.workspace = true
+
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
@@ -1,11 +1,11 @@
use crate::{BufferDiagnosticsEditor, ProjectDiagnosticsEditor, ToggleDiagnosticsRefresh};
use gpui::{Context, EventEmitter, ParentElement, Render, Window};
use language::DiagnosticEntry;
-use search::buffer_search;
use text::{Anchor, BufferId};
use ui::{Tooltip, prelude::*};
use workspace::{ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, item::ItemHandle};
use zed_actions::assistant::InlineAssist;
+use zed_actions::buffer_search;
pub struct ToolbarControls {
editor: Option<Box<dyn DiagnosticsToolbarEditor>>,
@@ -33,6 +33,7 @@ test-support = [
aho-corasick.workspace = true
anyhow.workspace = true
assets.workspace = true
+breadcrumbs.workspace = true
client.workspace = true
clock.workspace = true
collections.workspace = true
@@ -328,6 +328,7 @@ pub enum HideMouseCursorOrigin {
pub fn init(cx: &mut App) {
cx.set_global(GlobalBlameRenderer(Arc::new(())));
+ cx.set_global(breadcrumbs::RenderBreadcrumbText(render_breadcrumb_text));
workspace::register_project_item::<Editor>(cx);
workspace::FollowableViewRegistry::register::<Editor>(cx);
@@ -7776,7 +7776,7 @@ pub fn render_breadcrumb_text(
multibuffer_header: bool,
window: &mut Window,
cx: &App,
-) -> impl IntoElement {
+) -> gpui::AnyElement {
const MAX_SEGMENTS: usize = 12;
let element = h_flex().flex_grow().text_ui(cx);
@@ -32,7 +32,6 @@ gpui.workspace = true
language.workspace = true
menu.workspace = true
project.workspace = true
-schemars.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
@@ -22,15 +22,14 @@ use futures::channel::oneshot;
use gpui::{
Action, App, ClickEvent, Context, Entity, EventEmitter, Focusable, InteractiveElement as _,
IntoElement, KeyContext, ParentElement as _, Render, ScrollHandle, Styled, Subscription, Task,
- WeakEntity, Window, actions, div,
+ WeakEntity, Window, div,
};
use language::{Language, LanguageRegistry};
use project::{
search::SearchQuery,
search_history::{SearchHistory, SearchHistoryCursor},
};
-use schemars::JsonSchema;
-use serde::Deserialize;
+
use settings::Settings;
use std::{any::TypeId, sync::Arc};
use zed_actions::{outline::ToggleOutline, workspace::CopyPath, workspace::CopyRelativePath};
@@ -46,53 +45,12 @@ use workspace::{
},
};
-pub use registrar::DivRegistrar;
+pub use registrar::{DivRegistrar, register_pane_search_actions};
use registrar::{ForDeployed, ForDismissed, SearchActionsRegistrar};
const MAX_BUFFER_SEARCH_HISTORY_SIZE: usize = 50;
-/// Opens the buffer search interface with the specified configuration.
-#[derive(PartialEq, Clone, Deserialize, JsonSchema, Action)]
-#[action(namespace = buffer_search)]
-#[serde(deny_unknown_fields)]
-pub struct Deploy {
- #[serde(default = "util::serde::default_true")]
- pub focus: bool,
- #[serde(default)]
- pub replace_enabled: bool,
- #[serde(default)]
- pub selection_search_enabled: bool,
-}
-
-actions!(
- buffer_search,
- [
- /// Deploys the search and replace interface.
- DeployReplace,
- /// Dismisses the search bar.
- Dismiss,
- /// Focuses back on the editor.
- FocusEditor
- ]
-);
-
-impl Deploy {
- pub fn find() -> Self {
- Self {
- focus: true,
- replace_enabled: false,
- selection_search_enabled: false,
- }
- }
-
- pub fn replace() -> Self {
- Self {
- focus: true,
- replace_enabled: true,
- selection_search_enabled: false,
- }
- }
-}
+pub use zed_actions::buffer_search::{Deploy, DeployReplace, Dismiss, FocusEditor};
pub enum Event {
UpdateLocation,
@@ -1,5 +1,5 @@
-use gpui::{Action, Context, Div, Entity, InteractiveElement, Window, div};
-use workspace::Workspace;
+use gpui::{Action, App, Context, Div, Entity, InteractiveElement, Window, div};
+use workspace::{Pane, Workspace};
use crate::BufferSearchBar;
@@ -58,6 +58,57 @@ impl<T: 'static> SearchActionsRegistrar for DivRegistrar<'_, '_, T> {
}
}
+pub struct PaneDivRegistrar {
+ div: Option<Div>,
+ pane: Entity<Pane>,
+}
+
+impl PaneDivRegistrar {
+ pub fn new(div: Div, pane: Entity<Pane>) -> Self {
+ Self {
+ div: Some(div),
+ pane,
+ }
+ }
+
+ pub fn into_div(self) -> Div {
+ self.div.unwrap()
+ }
+}
+
+impl SearchActionsRegistrar for PaneDivRegistrar {
+ fn register_handler<A: Action>(&mut self, callback: impl ActionExecutor<A>) {
+ let pane = self.pane.clone();
+ self.div = self.div.take().map(|div| {
+ div.on_action(move |action: &A, window: &mut Window, cx: &mut App| {
+ let search_bar = pane
+ .read(cx)
+ .toolbar()
+ .read(cx)
+ .item_of_type::<BufferSearchBar>();
+ let should_notify = search_bar
+ .map(|search_bar| {
+ search_bar.update(cx, |search_bar, cx| {
+ callback.execute(search_bar, action, window, cx)
+ })
+ })
+ .unwrap_or(false);
+ if should_notify {
+ pane.update(cx, |_, cx| cx.notify());
+ } else {
+ cx.propagate();
+ }
+ })
+ });
+ }
+}
+
+pub fn register_pane_search_actions(div: Div, pane: Entity<Pane>) -> Div {
+ let mut registrar = PaneDivRegistrar::new(div, pane);
+ BufferSearchBar::register(&mut registrar);
+ registrar.into_div()
+}
+
/// Register actions for an active pane.
impl SearchActionsRegistrar for Workspace {
fn register_handler<A: Action>(&mut self, callback: impl ActionExecutor<A>) {
@@ -35,7 +35,7 @@ project.workspace = true
regex.workspace = true
task.workspace = true
schemars.workspace = true
-search.workspace = true
+
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
@@ -17,7 +17,7 @@ use gpui::{
};
use itertools::Itertools;
use project::{Fs, Project, ProjectEntryId};
-use search::{BufferSearchBar, buffer_search::DivRegistrar};
+
use settings::{Settings, TerminalDockPosition};
use task::{RevealStrategy, RevealTarget, Shell, ShellBuilder, SpawnInTerminal, TaskId};
use terminal::{Terminal, terminal_settings::TerminalSettings};
@@ -1238,12 +1238,13 @@ pub fn new_terminal_pane(
false
})));
- let buffer_search_bar = cx.new(|cx| {
- search::BufferSearchBar::new(Some(project.read(cx).languages().clone()), window, cx)
- });
+ let toolbar = pane.toolbar().clone();
+ if let Some(callbacks) = cx.try_global::<workspace::PaneSearchBarCallbacks>() {
+ let languages = Some(project.read(cx).languages().clone());
+ (callbacks.setup_search_bar)(languages, &toolbar, window, cx);
+ }
let breadcrumbs = cx.new(|_| Breadcrumbs::new());
- pane.toolbar().update(cx, |toolbar, cx| {
- toolbar.add_item(buffer_search_bar, window, cx);
+ toolbar.update(cx, |toolbar, cx| {
toolbar.add_item(breadcrumbs, window, cx);
});
@@ -1483,19 +1484,12 @@ impl EventEmitter<PanelEvent> for TerminalPanel {}
impl Render for TerminalPanel {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- let mut registrar = DivRegistrar::new(
- |panel, _, cx| {
- panel
- .active_pane
- .read(cx)
- .toolbar()
- .read(cx)
- .item_of_type::<BufferSearchBar>()
- },
- cx,
- );
- BufferSearchBar::register(&mut registrar);
- let registrar = registrar.into_div();
+ let registrar = cx
+ .try_global::<workspace::PaneSearchBarCallbacks>()
+ .map(|callbacks| {
+ (callbacks.wrap_div_with_search_actions)(div(), self.active_pane.clone())
+ })
+ .unwrap_or_else(div);
self.workspace
.update(cx, |workspace, cx| {
registrar.size_full().child(self.center.render(
@@ -1,11 +1,21 @@
use crate::ItemHandle;
use gpui::{
- AnyView, App, Context, Entity, EntityId, EventEmitter, KeyContext, ParentElement as _, Render,
- Styled, Window,
+ AnyView, App, Context, Div, Entity, EntityId, EventEmitter, Global, KeyContext,
+ ParentElement as _, Render, Styled, Window,
};
+use language::LanguageRegistry;
+use std::sync::Arc;
use ui::prelude::*;
use ui::{h_flex, v_flex};
+pub struct PaneSearchBarCallbacks {
+ pub setup_search_bar:
+ fn(Option<Arc<LanguageRegistry>>, &Entity<Toolbar>, &mut Window, &mut App),
+ pub wrap_div_with_search_actions: fn(Div, Entity<crate::Pane>) -> Div,
+}
+
+impl Global for PaneSearchBarCallbacks {}
+
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ToolbarItemEvent {
ChangeLocation(ToolbarItemLocation),
@@ -118,7 +118,9 @@ use std::{
};
use task::{DebugScenario, SharedTaskContext, SpawnInTerminal};
use theme::{ActiveTheme, GlobalTheme, SystemAppearance, ThemeSettings};
-pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
+pub use toolbar::{
+ PaneSearchBarCallbacks, Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView,
+};
pub use ui;
use ui::{Window, prelude::*};
use util::{
@@ -659,6 +659,15 @@ fn main() {
snippets_ui::init(cx);
channel::init(&app_state.client.clone(), app_state.user_store.clone(), cx);
search::init(cx);
+ cx.set_global(workspace::PaneSearchBarCallbacks {
+ setup_search_bar: |languages, toolbar, window, cx| {
+ let search_bar = cx.new(|cx| search::BufferSearchBar::new(languages, window, cx));
+ toolbar.update(cx, |toolbar, cx| {
+ toolbar.add_item(search_bar, window, cx);
+ });
+ },
+ wrap_div_with_search_actions: search::buffer_search::register_pane_search_actions,
+ });
vim::init(cx);
terminal_view::init(cx);
journal::init(app_state.clone(), cx);
@@ -187,6 +187,15 @@ fn run_visual_tests(project_path: PathBuf, update_baseline: bool) -> Result<()>
terminal_view::init(cx);
image_viewer::init(cx);
search::init(cx);
+ cx.set_global(workspace::PaneSearchBarCallbacks {
+ setup_search_bar: |languages, toolbar, window, cx| {
+ let search_bar = cx.new(|cx| search::BufferSearchBar::new(languages, window, cx));
+ toolbar.update(cx, |toolbar, cx| {
+ toolbar.add_item(search_bar, window, cx);
+ });
+ },
+ wrap_div_with_search_actions: search::buffer_search::register_pane_search_actions,
+ });
prompt_store::init(cx);
language_model::init(app_state.client.clone(), cx);
language_models::init(app_state.user_store.clone(), app_state.client.clone(), cx);
@@ -5067,6 +5067,16 @@ mod tests {
debugger_ui::init(cx);
initialize_workspace(app_state.clone(), prompt_builder, cx);
search::init(cx);
+ cx.set_global(workspace::PaneSearchBarCallbacks {
+ setup_search_bar: |languages, toolbar, window, cx| {
+ let search_bar =
+ cx.new(|cx| search::BufferSearchBar::new(languages, window, cx));
+ toolbar.update(cx, |toolbar, cx| {
+ toolbar.add_item(search_bar, window, cx);
+ });
+ },
+ wrap_div_with_search_actions: search::buffer_search::register_pane_search_actions,
+ });
app_state
})
}
@@ -62,6 +62,15 @@ pub fn init_visual_test(cx: &mut VisualTestAppContext) -> Arc<AppState> {
terminal_view::init(cx);
image_viewer::init(cx);
search::init(cx);
+ cx.set_global(workspace::PaneSearchBarCallbacks {
+ setup_search_bar: |languages, toolbar, window, cx| {
+ let search_bar = cx.new(|cx| search::BufferSearchBar::new(languages, window, cx));
+ toolbar.update(cx, |toolbar, cx| {
+ toolbar.add_item(search_bar, window, cx);
+ });
+ },
+ wrap_div_with_search_actions: search::buffer_search::register_pane_search_actions,
+ });
app_state
})
@@ -12,4 +12,5 @@ workspace = true
gpui.workspace = true
schemars.workspace = true
serde.workspace = true
+util.workspace = true
uuid.workspace = true
@@ -363,6 +363,54 @@ pub mod search {
]
);
}
+pub mod buffer_search {
+ use gpui::{Action, actions};
+ use schemars::JsonSchema;
+ use serde::Deserialize;
+
+ /// Opens the buffer search interface with the specified configuration.
+ #[derive(PartialEq, Clone, Deserialize, JsonSchema, Action)]
+ #[action(namespace = buffer_search)]
+ #[serde(deny_unknown_fields)]
+ pub struct Deploy {
+ #[serde(default = "util::serde::default_true")]
+ pub focus: bool,
+ #[serde(default)]
+ pub replace_enabled: bool,
+ #[serde(default)]
+ pub selection_search_enabled: bool,
+ }
+
+ impl Deploy {
+ pub fn find() -> Self {
+ Self {
+ focus: true,
+ replace_enabled: false,
+ selection_search_enabled: false,
+ }
+ }
+
+ pub fn replace() -> Self {
+ Self {
+ focus: true,
+ replace_enabled: true,
+ selection_search_enabled: false,
+ }
+ }
+ }
+
+ actions!(
+ buffer_search,
+ [
+ /// Deploys the search and replace interface.
+ DeployReplace,
+ /// Dismisses the search bar.
+ Dismiss,
+ /// Focuses back on the editor.
+ FocusEditor
+ ]
+ );
+}
pub mod settings_profile_selector {
use gpui::Action;
use schemars::JsonSchema;