diff --git a/Cargo.lock b/Cargo.lock index 1d43c57a302368647f4f5cb9ccc54a78d4cabaa2..26797dab4a91856a3b03c95610ffc967c9b6b356 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,6 @@ dependencies = [ "buffer_diff", "chrono", "collections", - "editor", "env_logger 0.11.8", "file_icons", "futures 0.3.31", @@ -25,6 +24,7 @@ dependencies = [ "language", "language_model", "markdown", + "multi_buffer", "parking_lot", "portable-pty", "project", @@ -38,6 +38,7 @@ dependencies = [ "telemetry", "tempfile", "terminal", + "text", "ui", "url", "urlencoding", @@ -272,17 +273,18 @@ dependencies = [ "chrono", "client", "collections", + "credentials_provider", "env_logger 0.11.8", "feature_flags", "fs", "futures 0.3.31", + "google_ai", "gpui", "gpui_tokio", "http_client", "indoc", "language", "language_model", - "language_models", "libc", "log", "nix 0.29.0", @@ -3370,6 +3372,7 @@ dependencies = [ "uuid", "workspace", "worktree", + "zed_actions", "zlog", ] @@ -5519,6 +5522,7 @@ dependencies = [ "tree-sitter-typescript", "tree-sitter-yaml", "ui", + "ui_input", "unicode-script", "unicode-segmentation", "unicode-width", @@ -6224,11 +6228,10 @@ dependencies = [ "gpui", "language", "menu", + "open_path_prompt", "picker", "pretty_assertions", "project", - "schemars", - "search", "serde", "serde_json", "settings", @@ -6237,6 +6240,7 @@ dependencies = [ "ui", "util", "workspace", + "zed_actions", "zlog", ] @@ -7271,6 +7275,7 @@ dependencies = [ "time_format", "tracing", "ui", + "ui_input", "unindent", "util", "watch", @@ -8432,11 +8437,11 @@ dependencies = [ "fuzzy", "gpui", "language", + "platform_title_bar", "project", "serde_json", "serde_json_lenient", "theme", - "title_bar", "ui", "util", "util_macros", @@ -9123,11 +9128,11 @@ version = "0.1.0" dependencies = [ "anyhow", "editor", - "file_finder", "file_icons", "fuzzy", "gpui", "language", + "open_path_prompt", "picker", "project", "settings", @@ -11136,6 +11141,27 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "open_path_prompt" +version = "0.1.0" +dependencies = [ + "editor", + "file_icons", + "futures 0.3.31", + "fuzzy", + "gpui", + "picker", + "project", + "schemars", + "serde", + "serde_json", + "settings", + "theme", + "ui", + "util", + "workspace", +] + [[package]] name = "open_router" version = "0.1.0" @@ -12159,7 +12185,9 @@ dependencies = [ "serde_json", "theme", "ui", + "ui_input", "workspace", + "zed_actions", ] [[package]] @@ -12254,6 +12282,20 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "platform_title_bar" +version = "0.1.0" +dependencies = [ + "gpui", + "settings", + "smallvec", + "theme", + "ui", + "windows 0.61.3", + "workspace", + "zed_actions", +] + [[package]] name = "plist" version = "1.8.0" @@ -13389,7 +13431,6 @@ dependencies = [ "editor", "extension", "extension_host", - "file_finder", "fs", "futures 0.3.31", "fuzzy", @@ -13401,6 +13442,7 @@ dependencies = [ "markdown", "menu", "node_runtime", + "open_path_prompt", "ordered-float 2.10.1", "paths", "picker", @@ -14057,14 +14099,15 @@ dependencies = [ "log", "menu", "picker", + "platform_title_bar", "prompt_store", "release_channel", "rope", "serde", "settings", "theme", - "title_bar", "ui", + "ui_input", "util", "workspace", "zed_actions", @@ -15060,6 +15103,7 @@ dependencies = [ "assets", "bm25", "client", + "component", "copilot_ui", "edit_prediction", "editor", @@ -15077,6 +15121,7 @@ dependencies = [ "node_runtime", "paths", "picker", + "platform_title_bar", "pretty_assertions", "project", "recent_projects", @@ -15092,7 +15137,6 @@ dependencies = [ "theme", "title_bar", "ui", - "ui_input", "util", "workspace", "zed_actions", @@ -15389,11 +15433,11 @@ dependencies = [ name = "snippets_ui" version = "0.1.0" dependencies = [ - "file_finder", "file_icons", "fuzzy", "gpui", "language", + "open_path_prompt", "paths", "picker", "settings", @@ -17051,6 +17095,7 @@ dependencies = [ "http_client", "menu", "notifications", + "platform_title_bar", "pretty_assertions", "project", "recent_projects", @@ -17325,12 +17370,12 @@ dependencies = [ "anyhow", "convert_case 0.8.0", "editor", - "file_finder", "futures 0.3.31", "fuzzy", "gpui", "language", "menu", + "open_path_prompt", "picker", "project", "ui", @@ -18000,11 +18045,7 @@ name = "ui_input" version = "0.1.0" dependencies = [ "component", - "editor", "gpui", - "menu", - "settings", - "theme", "ui", ] diff --git a/Cargo.toml b/Cargo.toml index 038ccf0e823f8e321f1ea815b843983e56e8714c..84fe05d2c150fc7503344e06830e926498fa292f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,6 +125,7 @@ members = [ "crates/ollama", "crates/onboarding", "crates/open_ai", + "crates/open_path_prompt", "crates/open_router", "crates/outline", "crates/outline_panel", @@ -187,6 +188,7 @@ members = [ "crates/theme_importer", "crates/theme_selector", "crates/time_format", + "crates/platform_title_bar", "crates/title_bar", "crates/toolchain_selector", "crates/ui", @@ -363,6 +365,7 @@ notifications = { path = "crates/notifications" } ollama = { path = "crates/ollama" } onboarding = { path = "crates/onboarding" } open_ai = { path = "crates/open_ai" } +open_path_prompt = { path = "crates/open_path_prompt" } open_router = { path = "crates/open_router", features = ["schemars"] } outline = { path = "crates/outline" } outline_panel = { path = "crates/outline_panel" } @@ -420,6 +423,7 @@ theme = { path = "crates/theme" } theme_extension = { path = "crates/theme_extension" } theme_selector = { path = "crates/theme_selector" } time_format = { path = "crates/time_format" } +platform_title_bar = { path = "crates/platform_title_bar" } title_bar = { path = "crates/title_bar" } toolchain_selector = { path = "crates/toolchain_selector" } ui = { path = "crates/ui" } diff --git a/crates/acp_thread/Cargo.toml b/crates/acp_thread/Cargo.toml index a32ceb46e5ae6226090c410ecc1318279b63d92d..c51b97c067e3bb801cb94f558c90c9eb43d9de39 100644 --- a/crates/acp_thread/Cargo.toml +++ b/crates/acp_thread/Cargo.toml @@ -24,7 +24,7 @@ anyhow.workspace = true buffer_diff.workspace = true chrono.workspace = true collections.workspace = true -editor.workspace = true +multi_buffer.workspace = true file_icons.workspace = true futures.workspace = true gpui.workspace = true @@ -44,6 +44,7 @@ smol.workspace = true task.workspace = true telemetry.workspace = true terminal.workspace = true +text.workspace = true ui.workspace = true url.workspace = true util.workspace = true @@ -52,7 +53,6 @@ watch.workspace = true urlencoding.workspace = true [dev-dependencies] -editor = { workspace = true, features = ["test-support"] } env_logger.workspace = true gpui = { workspace = true, "features" = ["test-support"] } indoc.workspace = true diff --git a/crates/acp_thread/src/acp_thread.rs b/crates/acp_thread/src/acp_thread.rs index d67e68b31ea96ac0aaa1304eb15195173309687f..7f0e1b89af6dd95d8b1bc219a55e17e5bceb0e8b 100644 --- a/crates/acp_thread/src/acp_thread.rs +++ b/crates/acp_thread/src/acp_thread.rs @@ -39,7 +39,6 @@ pub use terminal::*; use action_log::{ActionLog, ActionLogTelemetry}; use agent_client_protocol::{self as acp}; use anyhow::{Context as _, Result, anyhow}; -use editor::Bias; use futures::{FutureExt, channel::oneshot, future::BoxFuture}; use gpui::{AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Task, WeakEntity}; use itertools::Itertools; @@ -54,6 +53,7 @@ use std::process::ExitStatus; use std::rc::Rc; use std::time::{Duration, Instant}; use std::{fmt::Display, mem, path::PathBuf, sync::Arc}; +use text::Bias; use ui::App; use util::{ResultExt, get_default_system_shell_preferring_bash, paths::PathStyle}; use uuid::Uuid; diff --git a/crates/acp_thread/src/diff.rs b/crates/acp_thread/src/diff.rs index 722edf7008877c3fa195ad8ed6bcc68b6a70970a..d04cabb39d73050022200c881a8b7369482d618c 100644 --- a/crates/acp_thread/src/diff.rs +++ b/crates/acp_thread/src/diff.rs @@ -1,11 +1,11 @@ use anyhow::Result; use buffer_diff::BufferDiff; -use editor::{MultiBuffer, PathKey, multibuffer_context_lines}; use gpui::{App, AppContext, AsyncApp, Context, Entity, Subscription, Task}; use itertools::Itertools; use language::{ Anchor, Buffer, Capability, LanguageRegistry, OffsetRangeExt as _, Point, TextBuffer, }; +use multi_buffer::{MultiBuffer, PathKey, excerpt_context_lines}; use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc}; use util::ResultExt; @@ -63,7 +63,7 @@ impl Diff { PathKey::for_buffer(&buffer, cx), buffer.clone(), hunk_ranges, - multibuffer_context_lines(cx), + excerpt_context_lines(cx), cx, ); multibuffer.add_diff(diff, cx); @@ -300,7 +300,7 @@ impl PendingDiff { path_key, buffer, ranges, - multibuffer_context_lines(cx), + excerpt_context_lines(cx), cx, ); multibuffer.add_diff(buffer_diff.clone(), cx); @@ -326,7 +326,7 @@ impl PendingDiff { PathKey::for_buffer(&self.new_buffer, cx), self.new_buffer.clone(), ranges, - multibuffer_context_lines(cx), + excerpt_context_lines(cx), cx, ); let end = multibuffer.len(cx); diff --git a/crates/agent_servers/Cargo.toml b/crates/agent_servers/Cargo.toml index 6cad63fde98126f6c403deed36bcb50cd2a08166..391e37d9e7b0d7145e74ccecf7ac698b5b4d7a74 100644 --- a/crates/agent_servers/Cargo.toml +++ b/crates/agent_servers/Cargo.toml @@ -32,10 +32,11 @@ fs.workspace = true futures.workspace = true gpui.workspace = true gpui_tokio = { workspace = true, optional = true } +credentials_provider.workspace = true +google_ai.workspace = true http_client.workspace = true indoc.workspace = true language_model.workspace = true -language_models.workspace = true log.workspace = true project.workspace = true release_channel.workspace = true diff --git a/crates/agent_servers/src/e2e_tests.rs b/crates/agent_servers/src/e2e_tests.rs index 99e82c4ca9651d9935eb661540c78ba1008f9804..50740231b5cbe3352d6a0fa9ed6cf87da9f04c5f 100644 --- a/crates/agent_servers/src/e2e_tests.rs +++ b/crates/agent_servers/src/e2e_tests.rs @@ -2,7 +2,7 @@ use crate::{AgentServer, AgentServerDelegate}; use acp_thread::{AcpThread, AgentThreadEntry, ToolCall, ToolCallStatus}; use agent_client_protocol as acp; use futures::{FutureExt, StreamExt, channel::mpsc, select}; -use gpui::{AppContext, Entity, TestAppContext}; +use gpui::{Entity, TestAppContext}; use indoc::indoc; #[cfg(test)] use project::agent_server_store::BuiltinAgentServerSettings; @@ -410,9 +410,7 @@ pub async fn init_test(cx: &mut TestAppContext) -> Arc { let http_client = reqwest_client::ReqwestClient::user_agent("agent tests").unwrap(); cx.set_http_client(Arc::new(http_client)); let client = client::Client::production(cx); - let user_store = cx.new(|cx| client::UserStore::new(client.clone(), cx)); - language_model::init(client.clone(), cx); - language_models::init(user_store, client, cx); + language_model::init(client, cx); #[cfg(test)] project::agent_server_store::AllAgentServersSettings::override_global( diff --git a/crates/agent_servers/src/gemini.rs b/crates/agent_servers/src/gemini.rs index 8e0573e2735ebb692ec4e9417bc71e410970a590..1805e64a3a94dddd2b7b3c8762123b98a384ec23 100644 --- a/crates/agent_servers/src/gemini.rs +++ b/crates/agent_servers/src/gemini.rs @@ -4,11 +4,33 @@ use std::{any::Any, path::Path}; use crate::{AgentServer, AgentServerDelegate, load_proxy_env}; use acp_thread::AgentConnection; use anyhow::{Context as _, Result}; +use credentials_provider::CredentialsProvider; use gpui::{App, AppContext as _, SharedString, Task}; -use language_models::provider::google::GoogleLanguageModelProvider; +use language_model::{ApiKey, EnvVar}; use project::agent_server_store::{AllAgentServersSettings, GEMINI_NAME}; use settings::SettingsStore; +const GEMINI_API_KEY_VAR_NAME: &str = "GEMINI_API_KEY"; +const GOOGLE_AI_API_KEY_VAR_NAME: &str = "GOOGLE_AI_API_KEY"; + +fn api_key_for_gemini_cli(cx: &mut App) -> Task> { + let env_var = EnvVar::new(GEMINI_API_KEY_VAR_NAME.into()) + .or(EnvVar::new(GOOGLE_AI_API_KEY_VAR_NAME.into())); + if let Some(key) = env_var.value { + return Task::ready(Ok(key)); + } + let credentials_provider = ::global(cx); + let api_url = google_ai::API_URL.to_string(); + cx.spawn(async move |cx| { + Ok( + ApiKey::load_from_system_keychain(&api_url, credentials_provider.as_ref(), cx) + .await? + .key() + .to_string(), + ) + }) +} + #[derive(Clone)] pub struct Gemini; @@ -46,11 +68,7 @@ impl AgentServer for Gemini { cx.spawn(async move |cx| { extra_env.insert("SURFACE".to_owned(), "zed".to_owned()); - if let Some(api_key) = cx - .update(GoogleLanguageModelProvider::api_key_for_gemini_cli) - .await - .ok() - { + if let Some(api_key) = cx.update(api_key_for_gemini_cli).await.ok() { extra_env.insert("GEMINI_API_KEY".into(), api_key); } let (command, root_dir, login) = store diff --git a/crates/agent_ui/Cargo.toml b/crates/agent_ui/Cargo.toml index 39150df423b4db4bbdeba014c7f998e547678d1f..5ad35c41a1033b031e345fec95bc12c6fac62056 100644 --- a/crates/agent_ui/Cargo.toml +++ b/crates/agent_ui/Cargo.toml @@ -23,7 +23,6 @@ test-support = [ "reqwest_client", "workspace/test-support", "agent/test-support", - "rules_library/test-support" ] unit-eval = [] @@ -128,7 +127,6 @@ editor = { workspace = true, features = ["test-support"] } eval_utils.workspace = true gpui = { workspace = true, "features" = ["test-support"] } git_ui = { workspace = true, features = ["test-support"] } -rules_library = { workspace = true, features = ["test-support"] } indoc.workspace = true language = { workspace = true, "features" = ["test-support"] } languages = { workspace = true, features = ["test-support"] } diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs index 2927ec87d7acb57e05b3e272eb2eebfc6c72b50e..01a63111f8780434ad3be29ce3bae16226d522fb 100644 --- a/crates/agent_ui/src/acp/thread_view.rs +++ b/crates/agent_ui/src/acp/thread_view.rs @@ -9539,6 +9539,7 @@ pub(crate) mod tests { let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); theme::init(theme::LoadThemes::JustBase, cx); + editor::init(cx); release_channel::init(semver::Version::new(0, 0, 0), cx); prompt_store::init(cx) }); diff --git a/crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs b/crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs index db4968edf7e2be9e28695c4e1d0dce28444a73c5..09f993577ad6ec9ce27a664cfae5adaaa093c1ff 100644 --- a/crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs +++ b/crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs @@ -18,7 +18,7 @@ use workspace::{ModalView, Workspace}; fn single_line_input( label: impl Into, - placeholder: impl Into, + placeholder: &str, text: Option<&str>, tab_index: isize, window: &mut Window, @@ -31,9 +31,7 @@ fn single_line_input( .tab_stop(true); if let Some(text) = text { - input - .editor() - .update(cx, |editor, cx| editor.set_text(text, window, cx)); + input.set_text(text, window, cx); } input }) @@ -721,9 +719,7 @@ mod tests { cx.update(|window, cx| { let model_input = ModelInput::new(0, window, cx); model_input.name.update(cx, |input, cx| { - input.editor().update(cx, |editor, cx| { - editor.set_text("somemodel", window, cx); - }); + input.set_text("somemodel", window, cx); }); assert_eq!( model_input.capabilities.supports_tools, @@ -762,9 +758,7 @@ mod tests { cx.update(|window, cx| { let mut model_input = ModelInput::new(0, window, cx); model_input.name.update(cx, |input, cx| { - input.editor().update(cx, |editor, cx| { - editor.set_text("somemodel", window, cx); - }); + input.set_text("somemodel", window, cx); }); model_input.capabilities.supports_tools = ToggleState::Unselected; @@ -789,9 +783,7 @@ mod tests { cx.update(|window, cx| { let mut model_input = ModelInput::new(0, window, cx); model_input.name.update(cx, |input, cx| { - input.editor().update(cx, |editor, cx| { - editor.set_text("somemodel", window, cx); - }); + input.set_text("somemodel", window, cx); }); model_input.capabilities.supports_tools = ToggleState::Selected; @@ -817,6 +809,7 @@ mod tests { theme::init(theme::LoadThemes::JustBase, cx); language_model::init_settings(cx); + editor::init(cx); }); let fs = FakeFs::new(cx.executor()); @@ -837,9 +830,7 @@ mod tests { ) -> Option { fn set_text(input: &Entity, text: &str, window: &mut Window, cx: &mut App) { input.update(cx, |input, cx| { - input.editor().update(cx, |editor, cx| { - editor.set_text(text, window, cx); - }); + input.set_text(text, window, cx); }); } diff --git a/crates/agent_ui/src/inline_prompt_editor.rs b/crates/agent_ui/src/inline_prompt_editor.rs index db06fca8b051fba4788b775322613e172c4df69b..3c6b99f3466e2341e88e358c6d649ba828382848 100644 --- a/crates/agent_ui/src/inline_prompt_editor.rs +++ b/crates/agent_ui/src/inline_prompt_editor.rs @@ -8,7 +8,6 @@ use editor::display_map::{CreaseId, EditorMargins}; use editor::{AnchorRangeExt as _, MultiBufferOffset, ToOffset as _}; use editor::{ ContextMenuOptions, Editor, EditorElement, EditorEvent, EditorMode, EditorStyle, MultiBuffer, - actions::{MoveDown, MoveUp}, }; use fs::Fs; use gpui::{ @@ -31,7 +30,10 @@ use ui::{IconButtonShape, KeyBinding, PopoverMenuHandle, Tooltip, prelude::*}; use uuid::Uuid; use workspace::notifications::NotificationId; use workspace::{Toast, Workspace}; -use zed_actions::agent::ToggleModelSelector; +use zed_actions::{ + agent::ToggleModelSelector, + editor::{MoveDown, MoveUp}, +}; use crate::agent_model_selector::AgentModelSelector; use crate::buffer_codegen::{BufferCodegen, CodegenAlternative}; diff --git a/crates/agent_ui/src/text_thread_editor.rs b/crates/agent_ui/src/text_thread_editor.rs index 18c7026606b5bb29701eeeaf87ae046b650367f8..a16fcc716d1de13c6ba343ca3d77245d333aaf38 100644 --- a/crates/agent_ui/src/text_thread_editor.rs +++ b/crates/agent_ui/src/text_thread_editor.rs @@ -3542,6 +3542,7 @@ mod tests { fn init_test(cx: &mut App) { let settings_store = SettingsStore::test(cx); prompt_store::init(cx); + editor::init(cx); LanguageModelRegistry::test(cx); cx.set_global(settings_store); diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index 6079e50b9b0254169d18a8eeddbd633f3ef64a82..4b486698b53b7772335e93d4ea4f481e37779e9c 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -130,4 +130,5 @@ unindent.workspace = true util.workspace = true workspace = { workspace = true, features = ["test-support"] } worktree = { workspace = true, features = ["test-support"] } +zed_actions.workspace = true zlog.workspace = true diff --git a/crates/collab/src/tests/debug_panel_tests.rs b/crates/collab/src/tests/debug_panel_tests.rs index d1659e5114b9ba5bfd09514e092c60fa74ad4f8e..32856ee19a69051c2da1c31f0d8e70cdaac90ab8 100644 --- a/crates/collab/src/tests/debug_panel_tests.rs +++ b/crates/collab/src/tests/debug_panel_tests.rs @@ -933,8 +933,8 @@ async fn test_updated_breakpoints_send_to_dap( .unwrap(); editor_b.update_in(remote_cx, |editor, window, cx| { - editor.move_down(&editor::actions::MoveDown, window, cx); - editor.move_down(&editor::actions::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); }); @@ -972,8 +972,8 @@ async fn test_updated_breakpoints_send_to_dap( // remove the breakpoint that client B added editor_a.update_in(host_cx, |editor, window, cx| { - editor.move_down(&editor::actions::MoveDown, window, cx); - editor.move_down(&editor::actions::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); }); @@ -1029,7 +1029,7 @@ async fn test_updated_breakpoints_send_to_dap( // Add our own breakpoint now editor_a.update_in(host_cx, |editor, window, cx| { editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); - editor.move_up(&editor::actions::MoveUp, window, cx); + editor.move_up(&zed_actions::editor::MoveUp, window, cx); editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); }); @@ -1751,9 +1751,9 @@ async fn test_ignore_breakpoints( // .unwrap(); // local_editor.update_in(host_cx, |editor, window, cx| { - // editor.move_down(&editor::actions::MoveDown, window, cx); + // editor.move_down(&zed_actions::editor::MoveDown, window, cx); // editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); // Line 2 - // editor.move_down(&editor::actions::MoveDown, window, cx); + // editor.move_down(&zed_actions::editor::MoveDown, window, cx); // editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); // // Line 3 // }); diff --git a/crates/collab/src/tests/editor_tests.rs b/crates/collab/src/tests/editor_tests.rs index ca444024820be6b5b3a4165999d78ea9b642cc5e..4fee1e7858820124caadebcc73ea80fabf42fd1f 100644 --- a/crates/collab/src/tests/editor_tests.rs +++ b/crates/collab/src/tests/editor_tests.rs @@ -4185,8 +4185,8 @@ async fn test_add_breakpoints(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte // Client B adds breakpoint on line(2) editor_b.update_in(cx_b, |editor, window, cx| { - editor.move_down(&editor::actions::MoveDown, window, cx); - editor.move_down(&editor::actions::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); }); @@ -4214,8 +4214,8 @@ async fn test_add_breakpoints(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte // Client A removes last added breakpoint from client B editor_a.update_in(cx_a, |editor, window, cx| { - editor.move_down(&editor::actions::MoveDown, window, cx); - editor.move_down(&editor::actions::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); }); @@ -4243,8 +4243,8 @@ async fn test_add_breakpoints(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte // Client B removes first added breakpoint by client A editor_b.update_in(cx_b, |editor, window, cx| { - editor.move_up(&editor::actions::MoveUp, window, cx); - editor.move_up(&editor::actions::MoveUp, window, cx); + editor.move_up(&zed_actions::editor::MoveUp, window, cx); + editor.move_up(&zed_actions::editor::MoveUp, window, cx); editor.toggle_breakpoint(&editor::actions::ToggleBreakpoint, window, cx); }); diff --git a/crates/collab_ui/src/collab_panel/contact_finder.rs b/crates/collab_ui/src/collab_panel/contact_finder.rs index e5823d0e78d9bf73ae3ded307116f608d7c06b22..09543962a29defcf8e5dacf2eea69368a40422a9 100644 --- a/crates/collab_ui/src/collab_panel/contact_finder.rs +++ b/crates/collab_ui/src/collab_panel/contact_finder.rs @@ -28,7 +28,7 @@ impl ContactFinder { pub fn set_query(&mut self, query: String, window: &mut Window, cx: &mut Context) { self.picker.update(cx, |picker, cx| { - picker.set_query(query, window, cx); + picker.set_query(&query, window, cx); }); } } diff --git a/crates/component_preview/src/component_preview.rs b/crates/component_preview/src/component_preview.rs index 0f4a8d94baf9021f0d6911e693a435ee4ab5e524..c9fc17b7d552ba7aa83bd98e27f98b3da291f2c4 100644 --- a/crates/component_preview/src/component_preview.rs +++ b/crates/component_preview/src/component_preview.rs @@ -583,7 +583,7 @@ impl Render for ComponentPreview { if input.is_empty(cx) { String::new() } else { - input.editor().read(cx).text(cx) + input.text(cx) } }); diff --git a/crates/debugger_ui/src/new_process_modal.rs b/crates/debugger_ui/src/new_process_modal.rs index 862242a3d4fbc16b83f7424c4ccbe2927222424e..982edd7feca720666cf90b3b771e272f628076bd 100644 --- a/crates/debugger_ui/src/new_process_modal.rs +++ b/crates/debugger_ui/src/new_process_modal.rs @@ -848,7 +848,7 @@ impl ConfigureMode { fn load(&mut self, cwd: PathBuf, window: &mut Window, cx: &mut App) { self.cwd.update(cx, |input_field, cx| { if input_field.is_empty(cx) { - input_field.set_text(cwd.to_string_lossy(), window, cx); + input_field.set_text(&cwd.to_string_lossy(), window, cx); } }); } diff --git a/crates/debugger_ui/src/tests/debugger_panel.rs b/crates/debugger_ui/src/tests/debugger_panel.rs index 08d0e9c23ebcb8a8a6f1bbde31a1d0ebd8a9e94a..32c0bf01c91a328734da64bd844b93ae3d9fd7a1 100644 --- a/crates/debugger_ui/src/tests/debugger_panel.rs +++ b/crates/debugger_ui/src/tests/debugger_panel.rs @@ -1180,7 +1180,7 @@ async fn test_send_breakpoints_when_editor_has_been_saved( }); editor.update_in(cx, |editor, window, cx| { - editor.move_down(&actions::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx); }); @@ -1218,7 +1218,7 @@ async fn test_send_breakpoints_when_editor_has_been_saved( }); editor.update_in(cx, |editor, window, cx| { - editor.move_up(&actions::MoveUp, window, cx); + editor.move_up(&zed_actions::editor::MoveUp, window, cx); editor.insert("new text\n", window, cx); }); @@ -1312,18 +1312,18 @@ async fn test_unsetting_breakpoints_on_clear_breakpoint_action( }); first_editor.update_in(cx, |editor, window, cx| { - editor.move_down(&actions::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx); - editor.move_down(&actions::MoveDown, window, cx); - editor.move_down(&actions::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx); }); second_editor.update_in(cx, |editor, window, cx| { editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx); - editor.move_down(&actions::MoveDown, window, cx); - editor.move_down(&actions::MoveDown, window, cx); - editor.move_down(&actions::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); + editor.move_down(&zed_actions::editor::MoveDown, window, cx); editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx); }); diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index a94fcf4803b3c4b8886f3661f46053bbd510bf9b..8122af7053bc9af63768d9a38fa40d23d7208a6b 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -90,6 +90,7 @@ unicode-segmentation.workspace = true unicode-script.workspace = true unindent = { workspace = true, optional = true } ui.workspace = true +ui_input.workspace = true url.workspace = true util.workspace = true uuid.workspace = true diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index 3c99feb18359750ef9445071f872efe49304cbfd..8361a832a483bffd3d9daf0fe1d47061ad6cb5fc 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -602,8 +602,6 @@ actions!( LineDown, /// Moves cursor up one line. LineUp, - /// Moves cursor down. - MoveDown, /// Moves cursor left. MoveLeft, /// Moves the current line down. @@ -642,8 +640,6 @@ actions!( MoveToStartOfLargerSyntaxNode, /// Moves cursor to the end of the next larger syntax node. MoveToEndOfLargerSyntaxNode, - /// Moves cursor up. - MoveUp, /// Inserts a new line and moves cursor to it. Newline, /// Inserts a new line above the current line. diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 232ca9efa3943016065d79380effc7420416c1fd..1cd7c01966f787df7bebacb1c188ae8e448a8f7a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -108,7 +108,7 @@ use gpui::{ Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext, AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context, DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, - Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers, + Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage, Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled, Subscription, Task, TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, @@ -203,6 +203,7 @@ use ui::{ Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide, }; +use ui_input::ErasedEditor; use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc}; use workspace::{ CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal, @@ -212,6 +213,7 @@ use workspace::{ notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt}, searchable::{CollapseDirection, SearchEvent}, }; +use zed_actions::editor::{MoveDown, MoveUp}; use crate::{ code_context_menus::CompletionsMenuSource, @@ -372,6 +374,12 @@ pub fn init(cx: &mut App) { .detach(); } }); + _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| { + Arc::new(ErasedEditorImpl( + cx.new(|cx| Editor::single_line(window, cx)), + )) as Arc + }); + _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines); } pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) { @@ -27717,6 +27725,90 @@ impl InvalidationStack { } } +#[derive(Clone)] +struct ErasedEditorImpl(Entity); + +impl ui_input::ErasedEditor for ErasedEditorImpl { + fn text(&self, cx: &App) -> String { + self.0.read(cx).text(cx) + } + + fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) { + self.0.update(cx, |this, cx| { + this.set_text(text, window, cx); + }) + } + + fn clear(&self, window: &mut Window, cx: &mut App) { + self.0.update(cx, |this, cx| this.clear(window, cx)); + } + + fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) { + self.0.update(cx, |this, cx| { + this.set_placeholder_text(text, window, cx); + }); + } + + fn focus_handle(&self, cx: &App) -> FocusHandle { + self.0.read(cx).focus_handle(cx) + } + + fn render(&self, _: &mut Window, cx: &App) -> AnyElement { + let settings = ThemeSettings::get_global(cx); + let theme_color = cx.theme().colors(); + + let text_style = TextStyle { + font_family: settings.ui_font.family.clone(), + font_features: settings.ui_font.features.clone(), + font_size: rems(0.875).into(), + font_weight: settings.buffer_font.weight, + font_style: FontStyle::Normal, + line_height: relative(1.2), + color: theme_color.text, + ..Default::default() + }; + let editor_style = EditorStyle { + background: theme_color.ghost_element_background, + local_player: cx.theme().players().local(), + syntax: cx.theme().syntax().clone(), + text: text_style, + ..Default::default() + }; + EditorElement::new(&self.0, editor_style).into_any() + } + + fn as_any(&self) -> &dyn Any { + &self.0 + } + + fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) { + self.0.update(cx, |editor, cx| { + let editor_offset = editor.buffer().read(cx).len(cx); + editor.change_selections( + SelectionEffects::scroll(Autoscroll::Next), + window, + cx, + |s| s.select_ranges(Some(editor_offset..editor_offset)), + ); + }); + } + + fn subscribe( + &self, + mut callback: Box, + window: &mut Window, + cx: &mut App, + ) -> Subscription { + window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| { + let event = match event { + EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited, + EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred, + _ => return, + }; + (callback)(event, window, cx); + }) + } +} impl Default for InvalidationStack { fn default() -> Self { Self(Default::default()) diff --git a/crates/file_finder/Cargo.toml b/crates/file_finder/Cargo.toml index 46257b1f49dc4b5e225373d69576d2f54de8c79e..6a4135187816326e6f174d339a382365544889cd 100644 --- a/crates/file_finder/Cargo.toml +++ b/crates/file_finder/Cargo.toml @@ -21,10 +21,9 @@ futures.workspace = true fuzzy.workspace = true gpui.workspace = true menu.workspace = true +open_path_prompt.workspace = true picker.workspace = true project.workspace = true -schemars.workspace = true -search.workspace = true settings.workspace = true serde.workspace = true text.workspace = true @@ -32,6 +31,7 @@ theme.workspace = true ui.workspace = true util.workspace = true workspace.workspace = true +zed_actions.workspace = true [dev-dependencies] ctor.workspace = true diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index ef81ccb8c48b1a496df923f0fcd12b0375084ac1..73533c57f156cdfba04ca736eeed5b0d23d2ee8f 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -1,17 +1,11 @@ #[cfg(test)] mod file_finder_tests; -#[cfg(test)] -mod open_path_prompt_tests; - -pub mod file_finder_settings; -mod open_path_prompt; use futures::future::join_all; pub use open_path_prompt::OpenPathDelegate; use collections::HashMap; use editor::Editor; -use file_finder_settings::{FileFinderSettings, FileFinderWidth}; use file_icons::FileIcons; use fuzzy::{CharBag, PathMatch, PathMatchCandidate}; use gpui::{ @@ -19,12 +13,14 @@ use gpui::{ KeyContext, Modifiers, ModifiersChangedEvent, ParentElement, Render, Styled, Task, WeakEntity, Window, actions, rems, }; -use open_path_prompt::OpenPathPrompt; +use open_path_prompt::{ + OpenPathPrompt, + file_finder_settings::{FileFinderSettings, FileFinderWidth}, +}; use picker::{Picker, PickerDelegate}; use project::{ PathMatchCandidateSet, Project, ProjectPath, WorktreeId, worktree_store::WorktreeStore, }; -use search::ToggleIncludeIgnored; use settings::Settings; use std::{ borrow::Cow, @@ -51,6 +47,7 @@ use workspace::{ ModalView, OpenOptions, OpenVisible, SplitDirection, Workspace, item::PreviewTabsSettings, notifications::NotifyResultExt, pane, }; +use zed_actions::search::ToggleIncludeIgnored; actions!( file_finder, diff --git a/crates/git_ui/Cargo.toml b/crates/git_ui/Cargo.toml index f363b2e5313114c9583325f99eb46c953258708e..504a168c5df42e7a9185d7de9c14012bfc65a08a 100644 --- a/crates/git_ui/Cargo.toml +++ b/crates/git_ui/Cargo.toml @@ -57,6 +57,7 @@ theme.workspace = true time.workspace = true time_format.workspace = true ui.workspace = true +ui_input.workspace = true util.workspace = true watch.workspace = true workspace.workspace = true diff --git a/crates/git_ui/src/branch_picker.rs b/crates/git_ui/src/branch_picker.rs index 2130a612c84301aa32f473649c5a0292a3254b5e..05eed8f45eea7116c9f2336d624e0b57a68c4b92 100644 --- a/crates/git_ui/src/branch_picker.rs +++ b/crates/git_ui/src/branch_picker.rs @@ -20,6 +20,7 @@ use ui::{ Divider, HighlightedLabel, KeyBinding, ListHeader, ListItem, ListItemSpacing, Tooltip, prelude::*, }; +use ui_input::ErasedEditor; use util::ResultExt; use workspace::notifications::DetachAndPromptErr; use workspace::{ModalView, Workspace}; @@ -611,11 +612,12 @@ impl PickerDelegate for BranchListDelegate { fn render_editor( &self, - editor: &Entity, + editor: &Arc, _window: &mut Window, _cx: &mut Context>, ) -> Div { let focus_handle = self.focus_handle.clone(); + let editor = editor.as_any().downcast_ref::>().unwrap(); v_flex() .when( @@ -1325,6 +1327,7 @@ mod tests { let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); theme::init(theme::LoadThemes::JustBase, cx); + editor::init(cx); }); } diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 3f2f406136bdc3a8d9a813e37e264e97633bd214..32ab5349639eda1f423d70d4077ba255debf3817 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -4271,10 +4271,10 @@ impl GitPanel { .child( div() .pr_2p5() - .on_action(|&editor::actions::MoveUp, _, cx| { + .on_action(|&zed_actions::editor::MoveUp, _, cx| { cx.stop_propagation(); }) - .on_action(|&editor::actions::MoveDown, _, cx| { + .on_action(|&zed_actions::editor::MoveDown, _, cx| { cx.stop_propagation(); }) .child(EditorElement::new(&self.commit_editor, panel_editor_style)), diff --git a/crates/inspector_ui/Cargo.toml b/crates/inspector_ui/Cargo.toml index aaf40b2f8d11aa324f2f76e71988ada87415237b..b74b20191c2668e59b0ad44d3a8ccce165c5cba7 100644 --- a/crates/inspector_ui/Cargo.toml +++ b/crates/inspector_ui/Cargo.toml @@ -18,11 +18,11 @@ editor.workspace = true fuzzy.workspace = true gpui.workspace = true language.workspace = true +platform_title_bar.workspace = true project.workspace = true serde_json.workspace = true serde_json_lenient.workspace = true theme.workspace = true -title_bar.workspace = true ui.workspace = true util.workspace = true util_macros.workspace = true diff --git a/crates/inspector_ui/src/inspector.rs b/crates/inspector_ui/src/inspector.rs index 8be2db69e5be251f823c42c898b02fbd4139d20b..be5bb14ff84da92b7e64baa588a20de345c2442f 100644 --- a/crates/inspector_ui/src/inspector.rs +++ b/crates/inspector_ui/src/inspector.rs @@ -1,7 +1,7 @@ use anyhow::{Context as _, anyhow}; use gpui::{App, DivInspectorState, Inspector, InspectorElementId, IntoElement, Window}; +use platform_title_bar::PlatformTitleBar; use std::{cell::OnceCell, path::Path, sync::Arc}; -use title_bar::platform_title_bar::PlatformTitleBar; use ui::{Label, Tooltip, prelude::*}; use util::{ResultExt as _, command::new_smol_command}; use workspace::AppState; diff --git a/crates/keymap_editor/src/keymap_editor.rs b/crates/keymap_editor/src/keymap_editor.rs index adc9deaa21680042971e5ab5e1cd25dc61b1c92e..de22ae01b503fde9aabdd99be5253d7c4e3f1b71 100644 --- a/crates/keymap_editor/src/keymap_editor.rs +++ b/crates/keymap_editor/src/keymap_editor.rs @@ -2301,12 +2301,15 @@ impl KeybindingEditorModal { .context() .and_then(KeybindContextString::local) { - input.editor().update(cx, |editor, cx| { - editor.set_text(context.clone(), window, cx); - }); + input.set_text(&context, window, cx); } - let editor_entity = input.editor().clone(); + let editor_entity = input.editor(); + let editor_entity = editor_entity + .as_any() + .downcast_ref::>() + .unwrap() + .clone(); let workspace = workspace.clone(); cx.spawn(async move |_input_handle, cx| { let contexts = cx @@ -2350,7 +2353,12 @@ impl KeybindingEditorModal { .label("Action") .label_size(LabelSize::Default); - input.editor().update(cx, |editor, _cx| { + let editor_entity = input.editor(); + let editor_entity = editor_entity + .as_any() + .downcast_ref::>() + .unwrap(); + editor_entity.update(cx, |editor, _cx| { editor.set_completion_provider(Some(std::rc::Rc::new( ActionCompletionProvider::new(actions, humanized_names), ))); @@ -2417,7 +2425,7 @@ impl KeybindingEditorModal { return; }; - let action_name_str = action_editor.read(cx).editor.read(cx).text(cx); + let action_name_str = action_editor.read(cx).text(cx); let current_action = self.action_name_to_static.get(&action_name_str).copied(); if current_action == self.selected_action_name { @@ -2498,7 +2506,7 @@ impl KeybindingEditorModal { fn get_selected_action_name(&self, cx: &App) -> anyhow::Result<&'static str> { if let Some(selector) = self.action_editor.as_ref() { - let action_name_str = selector.read(cx).editor.read(cx).text(cx); + let action_name_str = selector.read(cx).text(cx); if action_name_str.is_empty() { anyhow::bail!("Action name is required"); @@ -2544,7 +2552,7 @@ impl KeybindingEditorModal { fn validate_context(&self, cx: &App) -> anyhow::Result> { let new_context = self .context_editor - .read_with(cx, |input, cx| input.editor().read(cx).text(cx)); + .read_with(cx, |input, cx| input.text(cx)); let Some(context) = new_context.is_empty().not().then_some(new_context) else { return Ok(None); }; @@ -2717,10 +2725,18 @@ impl KeybindingEditorModal { self.action_editor.as_ref().is_some_and(|action_editor| { let focus_handle = action_editor.read(cx).focus_handle(cx); let editor_entity = action_editor.read(cx).editor(); + let editor_entity = editor_entity + .as_any() + .downcast_ref::>() + .unwrap(); is_editor_showing_completions(&focus_handle, editor_entity) }) || { let focus_handle = self.context_editor.read(cx).focus_handle(cx); let editor_entity = self.context_editor.read(cx).editor(); + let editor_entity = editor_entity + .as_any() + .downcast_ref::>() + .unwrap(); is_editor_showing_completions(&focus_handle, editor_entity) } || self .action_arguments_editor diff --git a/crates/language_models/src/provider/google.rs b/crates/language_models/src/provider/google.rs index 2f5b3b3701d51e4f4faadae0f8ef83f8bf6b5b2f..af91c9613ef2a9fbbf720480a0b526ef650f61d4 100644 --- a/crates/language_models/src/provider/google.rs +++ b/crates/language_models/src/provider/google.rs @@ -1,6 +1,5 @@ use anyhow::{Context as _, Result}; use collections::BTreeMap; -use credentials_provider::CredentialsProvider; use futures::{FutureExt, Stream, StreamExt, future::BoxFuture}; use google_ai::{ FunctionDeclaration, GenerateContentResponse, GoogleModelMode, Part, SystemInstruction, @@ -32,7 +31,7 @@ use ui::{ButtonLink, ConfiguredApiCard, List, ListBulletItem, prelude::*}; use ui_input::InputField; use util::ResultExt; -use language_model::{ApiKey, ApiKeyState}; +use language_model::ApiKeyState; const PROVIDER_ID: LanguageModelProviderId = language_model::GOOGLE_PROVIDER_ID; const PROVIDER_NAME: LanguageModelProviderName = language_model::GOOGLE_PROVIDER_NAME; @@ -117,22 +116,6 @@ impl GoogleLanguageModelProvider { }) } - pub fn api_key_for_gemini_cli(cx: &mut App) -> Task> { - if let Some(key) = API_KEY_ENV_VAR.value.clone() { - return Task::ready(Ok(key)); - } - let credentials_provider = ::global(cx); - let api_url = Self::api_url(cx).to_string(); - cx.spawn(async move |cx| { - Ok( - ApiKey::load_from_system_keychain(&api_url, credentials_provider.as_ref(), cx) - .await? - .key() - .to_string(), - ) - }) - } - fn settings(cx: &App) -> &GoogleSettings { &crate::AllLanguageModelSettings::get_global(cx).google } diff --git a/crates/language_models/src/provider/ollama.rs b/crates/language_models/src/provider/ollama.rs index 79ac51a870782817723c7c32253946068d6570e3..da4b4fd51855625c5e21a062957b7e5154968267 100644 --- a/crates/language_models/src/provider/ollama.rs +++ b/crates/language_models/src/provider/ollama.rs @@ -613,7 +613,7 @@ impl ConfigurationView { let api_url_editor = cx.new(|cx| { let input = InputField::new(window, cx, OLLAMA_API_URL).label("API URL"); - input.set_text(OllamaLanguageModelProvider::api_url(cx), window, cx); + input.set_text(&OllamaLanguageModelProvider::api_url(cx), window, cx); input }); diff --git a/crates/language_selector/Cargo.toml b/crates/language_selector/Cargo.toml index 47ad9b9f8802a3964ababad593b7c6a604f1c98f..115509f512ae40f8f5ec9f8f588814cc4a3fa6af 100644 --- a/crates/language_selector/Cargo.toml +++ b/crates/language_selector/Cargo.toml @@ -15,11 +15,11 @@ doctest = false [dependencies] anyhow.workspace = true editor.workspace = true -file_finder.workspace = true file_icons.workspace = true fuzzy.workspace = true gpui.workspace = true language.workspace = true +open_path_prompt.workspace = true picker.workspace = true project.workspace = true settings.workspace = true diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index f826c429134073668bd0ab7d6f93567b42f6e62b..4c8de90c14c556270386acad34b47961326b3f36 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -3,14 +3,13 @@ mod active_buffer_language; pub use active_buffer_language::ActiveBufferLanguage; use anyhow::Context as _; use editor::Editor; -use file_finder::file_finder_settings::FileFinderSettings; -use file_icons::FileIcons; use fuzzy::{StringMatch, StringMatchCandidate, match_strings}; use gpui::{ App, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, ParentElement, Render, Styled, WeakEntity, Window, actions, }; use language::{Buffer, LanguageMatcher, LanguageName, LanguageRegistry}; +use open_path_prompt::file_finder_settings::FileFinderSettings; use picker::{Picker, PickerDelegate}; use project::Project; use settings::Settings; @@ -176,7 +175,7 @@ impl LanguageSelectorDelegate { matcher .path_suffixes .iter() - .find_map(|extension| FileIcons::get_icon(Path::new(extension), cx)) + .find_map(|extension| file_icons::FileIcons::get_icon(Path::new(extension), cx)) .map(Icon::from_path) .map(|icon| icon.color(Color::Muted)) } diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 283d99db4bd722d7e8a6eaf9d86d2622a191d8f8..deb92538253768d5cfb70ae969c6dab7f09122f2 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -44,7 +44,7 @@ use std::{ ops::{self, AddAssign, ControlFlow, Range, RangeBounds, Sub, SubAssign}, rc::Rc, str, - sync::Arc, + sync::{Arc, OnceLock}, time::Duration, }; use sum_tree::{Bias, Cursor, Dimension, Dimensions, SumTree, TreeMap}; @@ -59,6 +59,12 @@ use ztracing::instrument; pub use self::path_key::PathKey; +pub static EXCERPT_CONTEXT_LINES: OnceLock u32> = OnceLock::new(); + +pub fn excerpt_context_lines(cx: &App) -> u32 { + EXCERPT_CONTEXT_LINES.get().map(|f| f(cx)).unwrap_or(2) +} + #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ExcerptId(u32); diff --git a/crates/open_path_prompt/Cargo.toml b/crates/open_path_prompt/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..3418712abf9656cacd670882c3002cf50b3737d7 --- /dev/null +++ b/crates/open_path_prompt/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "open_path_prompt" +version = "0.1.0" +publish.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later" + +[dependencies] +file_icons.workspace = true +futures.workspace = true +fuzzy.workspace = true +gpui.workspace = true +picker.workspace = true +project.workspace = true +schemars.workspace = true +serde.workspace = true +settings.workspace = true +ui.workspace = true +util.workspace = true +workspace.workspace = true + +[dev-dependencies] +editor = {workspace = true, features = ["test-support"]} +gpui = {workspace = true, features = ["test-support"]} +serde_json.workspace = true +theme = {workspace = true, features = ["test-support"]} +workspace = {workspace = true, features = ["test-support"]} + +[lints] +workspace = true + +[lib] +path = "src/open_path_prompt.rs" diff --git a/crates/open_path_prompt/LICENSE-GPL b/crates/open_path_prompt/LICENSE-GPL new file mode 120000 index 0000000000000000000000000000000000000000..89e542f750cd3860a0598eff0dc34b56d7336dc4 --- /dev/null +++ b/crates/open_path_prompt/LICENSE-GPL @@ -0,0 +1 @@ +../../LICENSE-GPL \ No newline at end of file diff --git a/crates/file_finder/src/file_finder_settings.rs b/crates/open_path_prompt/src/file_finder_settings.rs similarity index 100% rename from crates/file_finder/src/file_finder_settings.rs rename to crates/open_path_prompt/src/file_finder_settings.rs diff --git a/crates/file_finder/src/open_path_prompt.rs b/crates/open_path_prompt/src/open_path_prompt.rs similarity index 99% rename from crates/file_finder/src/open_path_prompt.rs rename to crates/open_path_prompt/src/open_path_prompt.rs index f75d0ee99dc32bc1a1ab812328bba3d36fcb2953..dcc797baf890d72455b0aaf160c10d9cbad71d9e 100644 --- a/crates/file_finder/src/open_path_prompt.rs +++ b/crates/open_path_prompt/src/open_path_prompt.rs @@ -1,4 +1,9 @@ -use crate::file_finder_settings::FileFinderSettings; +pub mod file_finder_settings; + +#[cfg(test)] +mod open_path_prompt_tests; + +use file_finder_settings::FileFinderSettings; use file_icons::FileIcons; use futures::channel::oneshot; use fuzzy::{CharBag, StringMatch, StringMatchCandidate}; @@ -21,7 +26,7 @@ use util::{ }; use workspace::Workspace; -pub(crate) struct OpenPathPrompt; +pub struct OpenPathPrompt; pub struct OpenPathDelegate { tx: Option>>>, @@ -184,7 +189,7 @@ struct CandidateInfo { } impl OpenPathPrompt { - pub(crate) fn register( + pub fn register( workspace: &mut Workspace, _window: Option<&mut Window>, _: &mut Context, @@ -196,7 +201,7 @@ impl OpenPathPrompt { })); } - pub(crate) fn register_new_path( + pub fn register_new_path( workspace: &mut Workspace, _window: Option<&mut Window>, _: &mut Context, @@ -220,7 +225,7 @@ impl OpenPathPrompt { let delegate = OpenPathDelegate::new(tx, lister.clone(), creating_path, cx); let picker = Picker::uniform_list(delegate, window, cx).width(rems(34.)); let query = lister.default_query(cx); - picker.set_query(query, window, cx); + picker.set_query(&query, window, cx); picker }); } @@ -930,7 +935,7 @@ fn get_dir_and_suffix(query: String, path_style: PathStyle) -> (String, String) mod tests { use util::paths::PathStyle; - use crate::open_path_prompt::get_dir_and_suffix; + use super::get_dir_and_suffix; #[test] fn test_get_dir_and_suffix_with_windows_style() { diff --git a/crates/file_finder/src/open_path_prompt_tests.rs b/crates/open_path_prompt/src/open_path_prompt_tests.rs similarity index 99% rename from crates/file_finder/src/open_path_prompt_tests.rs rename to crates/open_path_prompt/src/open_path_prompt_tests.rs index 9af18c8a6bd82b389d4d18a997c3b5fe4a088730..32aa44a641b954d315b1d7311211eb87db2fc373 100644 --- a/crates/file_finder/src/open_path_prompt_tests.rs +++ b/crates/open_path_prompt/src/open_path_prompt_tests.rs @@ -347,7 +347,7 @@ fn init_test(cx: &mut TestAppContext) -> Arc { cx.update(|cx| { let state = AppState::test(cx); theme::init(theme::LoadThemes::JustBase, cx); - super::init(cx); + editor::init(cx); state }) @@ -370,7 +370,7 @@ fn build_open_path_prompt( .width(rems(34.)) .modal(false); let query = lister.default_query(cx); - picker.set_query(query, window, cx); + picker.set_query(&query, window, cx); picker }) }), diff --git a/crates/picker/Cargo.toml b/crates/picker/Cargo.toml index 1344d177f42f9ab6a15d8f5f1353b98eadfd175f..f85c55b9f27bcb8fd87101c341058e1a3962934e 100644 --- a/crates/picker/Cargo.toml +++ b/crates/picker/Cargo.toml @@ -17,14 +17,15 @@ test-support = [] [dependencies] anyhow.workspace = true -editor.workspace = true gpui.workspace = true menu.workspace = true schemars.workspace = true serde.workspace = true theme.workspace = true ui.workspace = true +ui_input.workspace = true workspace.workspace = true +zed_actions.workspace = true [dev-dependencies] ctor.workspace = true diff --git a/crates/picker/src/head.rs b/crates/picker/src/head.rs index 700896e3412bf96ceff25891c106d5a4dbc51460..18cff64fb6432f9dc77be067ca1d03214d3a6e6f 100644 --- a/crates/picker/src/head.rs +++ b/crates/picker/src/head.rs @@ -1,13 +1,13 @@ use std::sync::Arc; -use editor::{Editor, EditorEvent}; use gpui::{App, Entity, FocusHandle, Focusable, prelude::*}; use ui::prelude::*; +use ui_input::{ErasedEditor, ErasedEditorEvent}; /// The head of a [`Picker`](crate::Picker). pub(crate) enum Head { /// Picker has an editor that allows the user to filter the list. - Editor(Entity), + Editor(Arc), /// Picker has no head, it's just a list of items. Empty(Entity), @@ -16,17 +16,28 @@ pub(crate) enum Head { impl Head { pub fn editor( placeholder_text: Arc, - edit_handler: impl FnMut(&mut V, &Entity, &EditorEvent, &mut Window, &mut Context) - + 'static, + mut edit_handler: impl FnMut(&mut V, &ErasedEditorEvent, &mut Window, &mut Context) + 'static, window: &mut Window, cx: &mut Context, ) -> Self { - let editor = cx.new(|cx| { - let mut editor = Editor::single_line(window, cx); - editor.set_placeholder_text(placeholder_text.as_ref(), window, cx); - editor - }); - cx.subscribe_in(&editor, window, edit_handler).detach(); + let editor = (ui_input::ERASED_EDITOR_FACTORY.get().unwrap())(window, cx); + + editor.set_placeholder_text(placeholder_text.as_ref(), window, cx); + let this = cx.weak_entity(); + editor + .subscribe( + Box::new(move |event, window, cx| { + this.update(cx, |this, cx| (edit_handler)(this, &event, window, cx)) + .ok(); + }), + window, + cx, + ) + .detach(); + // cx.subscribe_in(&editor, window, |v, _, event, window, cx| { + // edit_handler(v, event, window, cx); + // }) + // .detach(); Self::Editor(editor) } diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 4d70918c573064ca24b0fdfa5add0775b275fd44..716653d89642fe6d8f457f145ed15b8972432a09 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -3,16 +3,12 @@ pub mod highlighted_match_with_paths; pub mod popover_menu; use anyhow::Result; -use editor::{ - Editor, SelectionEffects, - actions::{MoveDown, MoveUp}, - scroll::Autoscroll, -}; + use gpui::{ - Action, AnyElement, App, Bounds, ClickEvent, Context, DismissEvent, Entity, EventEmitter, - FocusHandle, Focusable, Length, ListSizingBehavior, ListState, MouseButton, MouseUpEvent, - Pixels, Render, ScrollStrategy, Task, UniformListScrollHandle, Window, actions, canvas, div, - list, prelude::*, uniform_list, + Action, AnyElement, App, Bounds, ClickEvent, Context, DismissEvent, EventEmitter, FocusHandle, + Focusable, Length, ListSizingBehavior, ListState, MouseButton, MouseUpEvent, Pixels, Render, + ScrollStrategy, Task, UniformListScrollHandle, Window, actions, canvas, div, list, prelude::*, + uniform_list, }; use head::Head; use schemars::JsonSchema; @@ -25,7 +21,9 @@ use ui::{ Color, Divider, DocumentationAside, DocumentationSide, Label, ListItem, ListItemSpacing, ScrollAxes, Scrollbars, WithScrollbar, prelude::*, utils::WithRemSize, v_flex, }; +use ui_input::{ErasedEditor, ErasedEditorEvent}; use workspace::{ModalView, item::Settings}; +use zed_actions::editor::{MoveDown, MoveUp}; enum ElementContainer { List(ListState), @@ -195,9 +193,9 @@ pub trait PickerDelegate: Sized + 'static { fn render_editor( &self, - editor: &Entity, - _window: &mut Window, - _cx: &mut Context>, + editor: &Arc, + window: &mut Window, + cx: &mut Context>, ) -> Div { v_flex() .when( @@ -210,7 +208,7 @@ pub trait PickerDelegate: Sized + 'static { .flex_none() .h_9() .px_2p5() - .child(editor.clone()), + .child(editor.render(window, cx)), ) .when( self.editor_position() == PickerEditorPosition::Start, @@ -480,7 +478,7 @@ impl Picker { .delegate .select_history(Direction::Down, &query, window, cx) { - self.set_query(query, window, cx); + self.set_query(&query, window, cx); return; } let count = self.delegate.match_count(); @@ -507,7 +505,7 @@ impl Picker { .delegate .select_history(Direction::Up, &query, window, cx) { - self.set_query(query, window, cx); + self.set_query(&query, window, cx); return; } let count = self.delegate.match_count(); @@ -606,7 +604,7 @@ impl Picker { cx: &mut Context, ) { if let Some(new_query) = self.delegate.confirm_completion(self.query(cx), window, cx) { - self.set_query(new_query, window, cx); + self.set_query(&new_query, window, cx); } else { cx.propagate() } @@ -627,7 +625,7 @@ impl Picker { fn do_confirm(&mut self, secondary: bool, window: &mut Window, cx: &mut Context) { if let Some(update_query) = self.delegate.confirm_update_query(window, cx) { - self.set_query(update_query, window, cx); + self.set_query(&update_query, window, cx); self.set_selected_index(0, Some(Direction::Down), false, window, cx); } else { self.delegate.confirm(secondary, window, cx) @@ -636,8 +634,7 @@ impl Picker { fn on_input_editor_event( &mut self, - _: &Entity, - event: &editor::EditorEvent, + event: &ErasedEditorEvent, window: &mut Window, cx: &mut Context, ) { @@ -645,16 +642,15 @@ impl Picker { panic!("unexpected call"); }; match event { - editor::EditorEvent::BufferEdited => { - let query = editor.read(cx).text(cx); + ErasedEditorEvent::BufferEdited => { + let query = editor.text(cx); self.update_matches(query, window, cx); } - editor::EditorEvent::Blurred => { + ErasedEditorEvent::Blurred => { if self.is_modal && window.is_window_active() { self.cancel(&menu::Cancel, window, cx); } } - _ => {} } } @@ -667,14 +663,13 @@ impl Picker { } } - pub fn refresh_placeholder(&mut self, window: &mut Window, cx: &mut App) { + pub fn refresh_placeholder(&mut self, window: &mut Window, cx: &mut Context) { match &self.head { Head::Editor(editor) => { let placeholder = self.delegate.placeholder_text(window, cx); - editor.update(cx, |editor, cx| { - editor.set_placeholder_text(placeholder.as_ref(), window, cx); - cx.notify(); - }); + + editor.set_placeholder_text(placeholder.as_ref(), window, cx); + cx.notify(); } Head::Empty(_) => {} } @@ -730,23 +725,15 @@ impl Picker { pub fn query(&self, cx: &App) -> String { match &self.head { - Head::Editor(editor) => editor.read(cx).text(cx), + Head::Editor(editor) => editor.text(cx), Head::Empty(_) => "".to_string(), } } - pub fn set_query(&self, query: impl Into>, window: &mut Window, cx: &mut App) { + pub fn set_query(&self, query: &str, window: &mut Window, cx: &mut App) { if let Head::Editor(editor) = &self.head { - editor.update(cx, |editor, cx| { - editor.set_text(query, window, cx); - let editor_offset = editor.buffer().read(cx).len(cx); - editor.change_selections( - SelectionEffects::scroll(Autoscroll::Next), - window, - cx, - |s| s.select_ranges(Some(editor_offset..editor_offset)), - ); - }); + editor.set_text(query, window, cx); + editor.move_selection_to_end(window, cx); } } diff --git a/crates/platform_title_bar/Cargo.toml b/crates/platform_title_bar/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..a8db1e37f206b90ca1cc18f933d5ab20ff45cdf1 --- /dev/null +++ b/crates/platform_title_bar/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "platform_title_bar" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "GPL-3.0-or-later" + +[lints] +workspace = true + +[lib] +path = "src/platform_title_bar.rs" +doctest = false + +[dependencies] +gpui.workspace = true +settings.workspace = true +smallvec.workspace = true +theme.workspace = true +ui.workspace = true +workspace.workspace = true +zed_actions.workspace = true + +[target.'cfg(windows)'.dependencies] +windows.workspace = true diff --git a/crates/platform_title_bar/LICENSE-GPL b/crates/platform_title_bar/LICENSE-GPL new file mode 120000 index 0000000000000000000000000000000000000000..89e542f750cd3860a0598eff0dc34b56d7336dc4 --- /dev/null +++ b/crates/platform_title_bar/LICENSE-GPL @@ -0,0 +1 @@ +../../LICENSE-GPL \ No newline at end of file diff --git a/crates/title_bar/src/platform_title_bar.rs b/crates/platform_title_bar/src/platform_title_bar.rs similarity index 96% rename from crates/title_bar/src/platform_title_bar.rs rename to crates/platform_title_bar/src/platform_title_bar.rs index 6ce7d089bb4641e2c1b7da710ebb0841fc51da4c..d53e8ae86cdba32b33e6959032667f9748de871e 100644 --- a/crates/title_bar/src/platform_title_bar.rs +++ b/crates/platform_title_bar/src/platform_title_bar.rs @@ -1,3 +1,6 @@ +mod platforms; +mod system_window_tabs; + use gpui::{ AnyElement, Context, Decorations, Entity, Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels, StatefulInteractiveElement, Styled, Window, WindowControlArea, div, px, @@ -11,6 +14,10 @@ use crate::{ system_window_tabs::SystemWindowTabs, }; +pub use system_window_tabs::{ + DraggedWindowTab, MergeAllWindows, MoveTabToNewWindow, ShowNextWindowTab, ShowPreviousWindowTab, +}; + pub struct PlatformTitleBar { id: ElementId, platform_style: PlatformStyle, @@ -62,6 +69,10 @@ impl PlatformTitleBar { { self.children = children.into_iter().collect(); } + + pub fn init(cx: &mut App) { + SystemWindowTabs::init(cx); + } } impl Render for PlatformTitleBar { diff --git a/crates/title_bar/src/platforms.rs b/crates/platform_title_bar/src/platforms.rs similarity index 100% rename from crates/title_bar/src/platforms.rs rename to crates/platform_title_bar/src/platforms.rs diff --git a/crates/title_bar/src/platforms/platform_linux.rs b/crates/platform_title_bar/src/platforms/platform_linux.rs similarity index 100% rename from crates/title_bar/src/platforms/platform_linux.rs rename to crates/platform_title_bar/src/platforms/platform_linux.rs diff --git a/crates/title_bar/src/platforms/platform_mac.rs b/crates/platform_title_bar/src/platforms/platform_mac.rs similarity index 100% rename from crates/title_bar/src/platforms/platform_mac.rs rename to crates/platform_title_bar/src/platforms/platform_mac.rs diff --git a/crates/title_bar/src/platforms/platform_windows.rs b/crates/platform_title_bar/src/platforms/platform_windows.rs similarity index 100% rename from crates/title_bar/src/platforms/platform_windows.rs rename to crates/platform_title_bar/src/platforms/platform_windows.rs diff --git a/crates/title_bar/src/system_window_tabs.rs b/crates/platform_title_bar/src/system_window_tabs.rs similarity index 100% rename from crates/title_bar/src/system_window_tabs.rs rename to crates/platform_title_bar/src/system_window_tabs.rs diff --git a/crates/recent_projects/Cargo.toml b/crates/recent_projects/Cargo.toml index 9bd6806077638218fae9edb4050e066a64c4a3d4..cda29486ee01c3dbd2ed38725349fb4b5ec299d7 100644 --- a/crates/recent_projects/Cargo.toml +++ b/crates/recent_projects/Cargo.toml @@ -24,7 +24,6 @@ db.workspace = true dev_container.workspace = true editor.workspace = true extension_host.workspace = true -file_finder.workspace = true futures.workspace = true fuzzy.workspace = true gpui.workspace = true @@ -33,6 +32,7 @@ log.workspace = true markdown.workspace = true menu.workspace = true node_runtime.workspace = true +open_path_prompt.workspace = true ordered-float.workspace = true paths.workspace = true picker.workspace = true diff --git a/crates/recent_projects/src/remote_servers.rs b/crates/recent_projects/src/remote_servers.rs index bf8716537f767cf8da1be0def4f8143456cf93dc..8640f8129d418b00bc6b1ea62ae3250cc400415a 100644 --- a/crates/recent_projects/src/remote_servers.rs +++ b/crates/recent_projects/src/remote_servers.rs @@ -7,7 +7,7 @@ use crate::{ }; use dev_container::start_dev_container; use editor::Editor; -use file_finder::OpenPathDelegate; + use futures::{FutureExt, channel::oneshot, future::Shared}; use gpui::{ AnyElement, App, ClickEvent, ClipboardItem, Context, DismissEvent, Entity, EventEmitter, @@ -16,6 +16,7 @@ use gpui::{ }; use language::Point; use log::{debug, info}; +use open_path_prompt::OpenPathDelegate; use paths::{global_ssh_config_file, user_ssh_config_file}; use picker::Picker; use project::{Fs, Project}; @@ -222,13 +223,13 @@ impl ProjectPicker { ) -> Entity { let (tx, rx) = oneshot::channel(); let lister = project::DirectoryLister::Project(project.clone()); - let delegate = file_finder::OpenPathDelegate::new(tx, lister, false, cx); + let delegate = open_path_prompt::OpenPathDelegate::new(tx, lister, false, cx); let picker = cx.new(|cx| { let picker = Picker::uniform_list(delegate, window, cx) .width(rems(34.)) .modal(false); - picker.set_query(home_dir.to_string(), window, cx); + picker.set_query(&home_dir.to_string(), window, cx); picker }); diff --git a/crates/rules_library/Cargo.toml b/crates/rules_library/Cargo.toml index d9f1b2ced8026a50052cc84172733a498b088a17..59c298de923f98135c99fca0c8da2fa42ac2e17e 100644 --- a/crates/rules_library/Cargo.toml +++ b/crates/rules_library/Cargo.toml @@ -11,8 +11,6 @@ workspace = true [lib] path = "src/rules_library.rs" -[features] -test-support = ["title_bar/test-support"] [dependencies] anyhow.workspace = true @@ -24,14 +22,15 @@ language_model.workspace = true log.workspace = true menu.workspace = true picker.workspace = true +platform_title_bar.workspace = true prompt_store.workspace = true release_channel.workspace = true rope.workspace = true serde.workspace = true settings.workspace = true theme.workspace = true -title_bar.workspace = true ui.workspace = true +ui_input.workspace = true util.workspace = true workspace.workspace = true zed_actions.workspace = true diff --git a/crates/rules_library/src/rules_library.rs b/crates/rules_library/src/rules_library.rs index 09089a6bcba83b4159b346c0e9da2dfd53289389..ce8b24d2d1bc6e64372333ed5d17c55dbc1460c0 100644 --- a/crates/rules_library/src/rules_library.rs +++ b/crates/rules_library/src/rules_library.rs @@ -12,6 +12,7 @@ use language_model::{ ConfiguredModel, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, Role, }; use picker::{Picker, PickerDelegate}; +use platform_title_bar::PlatformTitleBar; use release_channel::ReleaseChannel; use rope::Rope; use settings::Settings; @@ -20,8 +21,8 @@ use std::sync::Arc; use std::sync::atomic::AtomicBool; use std::time::Duration; use theme::ThemeSettings; -use title_bar::platform_title_bar::PlatformTitleBar; use ui::{Divider, ListItem, ListItemSpacing, ListSubHeader, Tooltip, prelude::*}; +use ui_input::ErasedEditor; use util::{ResultExt, TryFutureExt}; use workspace::{Workspace, WorkspaceSettings, client_side_decorations}; use zed_actions::assistant::InlineAssist; @@ -445,10 +446,12 @@ impl PickerDelegate for RulePickerDelegate { fn render_editor( &self, - editor: &Entity, + editor: &Arc, _: &mut Window, cx: &mut Context>, ) -> Div { + let editor = editor.as_any().downcast_ref::>().unwrap(); + h_flex() .py_1() .px_1p5() @@ -983,7 +986,7 @@ impl RulesLibrary { fn move_down_from_title( &mut self, - _: &editor::actions::MoveDown, + _: &zed_actions::editor::MoveDown, window: &mut Window, cx: &mut Context, ) { @@ -996,7 +999,7 @@ impl RulesLibrary { fn move_up_from_body( &mut self, - _: &editor::actions::MoveUp, + _: &zed_actions::editor::MoveUp, window: &mut Window, cx: &mut Context, ) { diff --git a/crates/search/Cargo.toml b/crates/search/Cargo.toml index 02eb611fc22570c9028c21bc00187c627198475c..b08b6396aa638d027a15d6c3926b676a24650791 100644 --- a/crates/search/Cargo.toml +++ b/crates/search/Cargo.toml @@ -58,4 +58,3 @@ workspace = { workspace = true, features = ["test-support"] } [package.metadata.cargo-machete] ignored = ["tracing"] - diff --git a/crates/search/src/search.rs b/crates/search/src/search.rs index 3aa40894ea91ed7af3441fad210f6ce0f9e1dd53..4f261b94f0f30395aa262db8964ecf421c11525d 100644 --- a/crates/search/src/search.rs +++ b/crates/search/src/search.rs @@ -8,6 +8,7 @@ use ui::{ButtonStyle, IconButton, IconButtonShape}; use ui::{Tooltip, prelude::*}; use workspace::notifications::NotificationId; use workspace::{Toast, Workspace}; +pub use zed_actions::search::ToggleIncludeIgnored; pub use search_status_button::SEARCH_ICON; @@ -33,8 +34,6 @@ actions!( ToggleWholeWord, /// Toggles case-sensitive search. ToggleCaseSensitive, - /// Toggles searching in ignored files. - ToggleIncludeIgnored, /// Toggles regular expression mode. ToggleRegex, /// Toggles the replace interface. diff --git a/crates/settings_ui/Cargo.toml b/crates/settings_ui/Cargo.toml index 6d65513d250876e901bc624ba1104767358a854b..a3a2b2701484cc90a73d8efe8bb2bbfb5a5cbbe5 100644 --- a/crates/settings_ui/Cargo.toml +++ b/crates/settings_ui/Cargo.toml @@ -18,6 +18,7 @@ test-support = [] [dependencies] anyhow.workspace = true bm25 = "2.3.2" +component.workspace = true copilot_ui.workspace = true edit_prediction.workspace = true editor.workspace = true @@ -34,6 +35,7 @@ log.workspace = true menu.workspace = true paths.workspace = true picker.workspace = true +platform_title_bar.workspace = true project.workspace = true release_channel.workspace = true schemars.workspace = true @@ -43,8 +45,6 @@ settings.workspace = true strum.workspace = true telemetry.workspace = true theme.workspace = true -title_bar.workspace = true -ui_input.workspace = true ui.workspace = true util.workspace = true workspace.workspace = true diff --git a/crates/settings_ui/src/components.rs b/crates/settings_ui/src/components.rs index f9754b0c749a77423930ef881e5b60ad3535b83d..e122aebe249262c517a01815582eb3f7da44a8f2 100644 --- a/crates/settings_ui/src/components.rs +++ b/crates/settings_ui/src/components.rs @@ -2,6 +2,7 @@ mod dropdown; mod font_picker; mod icon_theme_picker; mod input_field; +mod number_field; mod section_items; mod theme_picker; @@ -9,5 +10,6 @@ pub use dropdown::*; pub use font_picker::font_picker; pub use icon_theme_picker::icon_theme_picker; pub use input_field::*; +pub use number_field::*; pub use section_items::*; pub use theme_picker::theme_picker; diff --git a/crates/ui_input/src/number_field.rs b/crates/settings_ui/src/components/number_field.rs similarity index 97% rename from crates/ui_input/src/number_field.rs rename to crates/settings_ui/src/components/number_field.rs index 84262a9617718b1f3741ea51b881361ee3f9e7d3..9ddac4263e2e919d86bf923f68626c6a228eef3e 100644 --- a/crates/ui_input/src/number_field.rs +++ b/crates/settings_ui/src/components/number_field.rs @@ -5,7 +5,7 @@ use std::{ str::FromStr, }; -use editor::{Editor, actions::MoveDown, actions::MoveUp}; +use editor::Editor; use gpui::{ ClickEvent, Entity, FocusHandle, Focusable, FontWeight, Modifiers, TextAlign, TextStyleRefinement, WeakEntity, @@ -16,6 +16,7 @@ use settings::{ MinimumContrast, }; use ui::prelude::*; +use zed_actions::editor::{MoveDown, MoveUp}; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum NumberFieldMode { @@ -316,26 +317,6 @@ impl NumberField { } } - pub fn format(mut self, format: impl FnOnce(&T) -> String + 'static) -> Self { - self.format = Box::new(format); - self - } - - pub fn small_step(mut self, step: T) -> Self { - self.small_step = step; - self - } - - pub fn normal_step(mut self, step: T) -> Self { - self.step = step; - self - } - - pub fn large_step(mut self, step: T) -> Self { - self.large_step = step; - self - } - pub fn min(mut self, min: T) -> Self { self.min_value = min; self @@ -351,14 +332,6 @@ impl NumberField { self } - pub fn on_reset( - mut self, - on_reset: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static, - ) -> Self { - self.on_reset = Some(Box::new(on_reset)); - self - } - pub fn tab_index(mut self, tab_index: isize) -> Self { self.tab_index = Some(tab_index); self diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 831cd2e455cd7986843b02a187f74f9c885deac0..9d6ec1fa4aa373bb808a00bf563ab15150fcf4ce 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -14,6 +14,7 @@ use gpui::{ }; use language::Buffer; +use platform_title_bar::PlatformTitleBar; use project::{Project, ProjectPath, Worktree, WorktreeId}; use release_channel::ReleaseChannel; use schemars::JsonSchema; @@ -32,20 +33,19 @@ use std::{ time::Duration, }; use theme::ThemeSettings; -use title_bar::platform_title_bar::PlatformTitleBar; use ui::{ Banner, ContextMenu, Divider, DropdownMenu, DropdownStyle, IconButtonShape, KeyBinding, KeybindingHint, PopoverMenu, Scrollbars, Switch, Tooltip, TreeViewItem, WithScrollbar, prelude::*, }; -use ui_input::{NumberField, NumberFieldMode, NumberFieldType}; + use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath}; use workspace::{AppState, OpenOptions, OpenVisible, Workspace, client_side_decorations}; use zed_actions::{OpenProjectSettings, OpenSettings, OpenSettingsAt}; use crate::components::{ - EnumVariantDropdown, SettingsInputField, SettingsSectionHeader, font_picker, icon_theme_picker, - theme_picker, + EnumVariantDropdown, NumberField, NumberFieldMode, NumberFieldType, SettingsInputField, + SettingsSectionHeader, font_picker, icon_theme_picker, theme_picker, }; const NAVBAR_CONTAINER_TAB_INDEX: isize = 0; diff --git a/crates/snippets_ui/Cargo.toml b/crates/snippets_ui/Cargo.toml index 3139a41dada1c42f94de41d37e69be68a8de49a5..7335accac0c2ec930c3c13a9bbcd5cf5a866ea3e 100644 --- a/crates/snippets_ui/Cargo.toml +++ b/crates/snippets_ui/Cargo.toml @@ -12,11 +12,11 @@ workspace = true path = "src/snippets_ui.rs" [dependencies] -file_finder.workspace = true file_icons.workspace = true fuzzy.workspace = true gpui.workspace = true language.workspace = true +open_path_prompt.workspace = true paths.workspace = true picker.workspace = true settings.workspace = true diff --git a/crates/snippets_ui/src/snippets_ui.rs b/crates/snippets_ui/src/snippets_ui.rs index cfe41144ba955f34ac527f605940835015e1d218..c881d5276e6f96c5fc9b4db802aa3731e843852f 100644 --- a/crates/snippets_ui/src/snippets_ui.rs +++ b/crates/snippets_ui/src/snippets_ui.rs @@ -1,4 +1,3 @@ -use file_finder::file_finder_settings::FileFinderSettings; use file_icons::FileIcons; use fuzzy::{StringMatch, StringMatchCandidate, match_strings}; use gpui::{ @@ -6,6 +5,7 @@ use gpui::{ WeakEntity, Window, actions, }; use language::{LanguageMatcher, LanguageName, LanguageRegistry}; +use open_path_prompt::file_finder_settings::FileFinderSettings; use paths::snippets_dir; use picker::{Picker, PickerDelegate}; use settings::Settings; diff --git a/crates/title_bar/Cargo.toml b/crates/title_bar/Cargo.toml index a17395e33ff3b3e4794e2cf3cda48c9a104453bd..01d737b72db4acc7ef4dcd13e9d9bde06001d74f 100644 --- a/crates/title_bar/Cargo.toml +++ b/crates/title_bar/Cargo.toml @@ -31,6 +31,7 @@ test-support = [ [dependencies] anyhow.workspace = true auto_update.workspace = true +platform_title_bar.workspace = true call.workspace = true channel.workspace = true chrono.workspace = true diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index 4da50918937b1b3b7d17a34afbac822f87281dd1..17998c4173f13d2338cb3e78e18e02006ad0e4be 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -1,19 +1,16 @@ mod application_menu; pub mod collab; mod onboarding_banner; -pub mod platform_title_bar; -mod platforms; mod project_dropdown; -mod system_window_tabs; mod title_bar_settings; #[cfg(feature = "stories")] mod stories; -use crate::{ - application_menu::{ApplicationMenu, show_menus}, - platform_title_bar::PlatformTitleBar, - system_window_tabs::SystemWindowTabs, +use crate::application_menu::{ApplicationMenu, show_menus}; +pub use platform_title_bar::{ + self, DraggedWindowTab, MergeAllWindows, MoveTabToNewWindow, PlatformTitleBar, + ShowNextWindowTab, ShowPreviousWindowTab, }; #[cfg(not(target_os = "macos"))] @@ -69,7 +66,7 @@ actions!( ); pub fn init(cx: &mut App) { - SystemWindowTabs::init(cx); + platform_title_bar::PlatformTitleBar::init(cx); cx.observe_new(|workspace: &mut Workspace, window, cx| { let Some(window) = window else { diff --git a/crates/toolchain_selector/Cargo.toml b/crates/toolchain_selector/Cargo.toml index 94a655b7270c8e084a7b74b7711bb62c0a6a18aa..09f9acceabd20c60459ce2464ae045766ffd0227 100644 --- a/crates/toolchain_selector/Cargo.toml +++ b/crates/toolchain_selector/Cargo.toml @@ -9,12 +9,12 @@ license = "GPL-3.0-or-later" anyhow.workspace = true convert_case.workspace = true editor.workspace = true -file_finder.workspace = true futures.workspace = true fuzzy.workspace = true gpui.workspace = true language.workspace = true menu.workspace = true +open_path_prompt.workspace = true picker.workspace = true project.workspace = true ui.workspace = true diff --git a/crates/toolchain_selector/src/toolchain_selector.rs b/crates/toolchain_selector/src/toolchain_selector.rs index 62a1ad33eba6942a96a72e10671b992c303062eb..5d2e63f9737b099fdd085cde357dfc0d7f76cd36 100644 --- a/crates/toolchain_selector/src/toolchain_selector.rs +++ b/crates/toolchain_selector/src/toolchain_selector.rs @@ -4,7 +4,6 @@ pub use active_toolchain::ActiveToolchain; use anyhow::Context as _; use convert_case::Casing as _; use editor::Editor; -use file_finder::OpenPathDelegate; use futures::channel::oneshot; use fuzzy::{StringMatch, StringMatchCandidate, match_strings}; use gpui::{ @@ -13,6 +12,7 @@ use gpui::{ actions, pulsating_between, }; use language::{Language, LanguageName, Toolchain, ToolchainScope}; +use open_path_prompt::OpenPathDelegate; use picker::{Picker, PickerDelegate}; use project::{DirectoryLister, Project, ProjectPath, Toolchains, WorktreeId}; use std::{ @@ -82,7 +82,7 @@ enum PathInputState { enum AddState { Path { - picker: Entity>, + picker: Entity>, error: Option>, input_state: PathInputState, _subscription: Subscription, @@ -226,11 +226,7 @@ impl AddToolchainState { Self::create_path_browser_delegate(this.project.clone(), cx); picker.update(cx, |picker, cx| { *picker = Picker::uniform_list(delegate, window, cx); - picker.set_query( - Arc::from(path.to_string_lossy().as_ref()), - window, - cx, - ); + picker.set_query(path.to_string_lossy().as_ref(), window, cx); }); *input_state = Self::wait_for_path(rx, window, cx); this.focus_handle(cx).focus(window, cx); diff --git a/crates/ui_input/Cargo.toml b/crates/ui_input/Cargo.toml index 4e7b08241dff8e3e5c00052826485c309449d205..fef5216266f866e56841e6da865ac91228928919 100644 --- a/crates/ui_input/Cargo.toml +++ b/crates/ui_input/Cargo.toml @@ -13,11 +13,7 @@ path = "src/ui_input.rs" [dependencies] component.workspace = true -editor.workspace = true gpui.workspace = true -menu.workspace = true -settings.workspace = true -theme.workspace = true ui.workspace = true [features] diff --git a/crates/ui_input/src/input_field.rs b/crates/ui_input/src/input_field.rs index 2bae8c172dcecbc94aa591297831c4f43279197b..59a05497627838364b4037c44b236ab70c2b3c6b 100644 --- a/crates/ui_input/src/input_field.rs +++ b/crates/ui_input/src/input_field.rs @@ -1,11 +1,12 @@ use component::{example_group, single_example}; -use editor::{Editor, EditorElement, EditorStyle}; -use gpui::{App, Entity, FocusHandle, Focusable, FontStyle, Hsla, Length, TextStyle}; -use settings::Settings; + +use gpui::{App, FocusHandle, Focusable, Hsla, Length}; use std::sync::Arc; -use theme::ThemeSettings; + use ui::prelude::*; +use crate::ErasedEditor; + pub struct InputFieldStyle { text_color: Hsla, background_color: Hsla, @@ -25,16 +26,12 @@ pub struct InputField { label_size: LabelSize, /// The placeholder text for the text field. placeholder: SharedString, - /// Exposes the underlying [`Entity`] to allow for customizing the editor beyond the provided API. - /// - /// This likely will only be public in the short term, ideally the API will be expanded to cover necessary use cases. - pub editor: Entity, + + editor: Arc, /// An optional icon that is displayed at the start of the text field. /// /// For example, a magnifying glass icon in a search field. start_icon: Option, - /// Whether the text field is disabled. - disabled: bool, /// The minimum width of for the input min_width: Length, /// The tab index for keyboard navigation order. @@ -50,22 +47,19 @@ impl Focusable for InputField { } impl InputField { - pub fn new(window: &mut Window, cx: &mut App, placeholder: impl Into) -> Self { - let placeholder_text = placeholder.into(); - - let editor = cx.new(|cx| { - let mut input = Editor::single_line(window, cx); - input.set_placeholder_text(&placeholder_text, window, cx); - input - }); + pub fn new(window: &mut Window, cx: &mut App, placeholder_text: &str) -> Self { + let editor_factory = crate::ERASED_EDITOR_FACTORY + .get() + .expect("ErasedEditorFactory to be initialized"); + let editor = (editor_factory)(window, cx); + editor.set_placeholder_text(placeholder_text, window, cx); Self { label: None, label_size: LabelSize::Small, - placeholder: placeholder_text, + placeholder: SharedString::new(placeholder_text), editor, start_icon: None, - disabled: false, min_width: px(192.).into(), tab_index: None, tab_stop: true, @@ -102,77 +96,39 @@ impl InputField { self } - pub fn set_disabled(&mut self, disabled: bool, cx: &mut Context) { - self.disabled = disabled; - self.editor - .update(cx, |editor, _| editor.set_read_only(disabled)) - } - pub fn is_empty(&self, cx: &App) -> bool { - self.editor().read(cx).text(cx).trim().is_empty() + self.editor().text(cx).trim().is_empty() } - pub fn editor(&self) -> &Entity { + pub fn editor(&self) -> &Arc { &self.editor } pub fn text(&self, cx: &App) -> String { - self.editor().read(cx).text(cx) + self.editor().text(cx) } pub fn clear(&self, window: &mut Window, cx: &mut App) { - self.editor() - .update(cx, |editor, cx| editor.clear(window, cx)) + self.editor().clear(window, cx) } - pub fn set_text(&self, text: impl Into>, window: &mut Window, cx: &mut App) { - self.editor() - .update(cx, |editor, cx| editor.set_text(text, window, cx)) + pub fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) { + self.editor().set_text(text, window, cx) } } impl Render for InputField { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let editor = self.editor.clone(); - let settings = ThemeSettings::get_global(cx); + let theme_color = cx.theme().colors(); - let mut style = InputFieldStyle { + let style = InputFieldStyle { text_color: theme_color.text, background_color: theme_color.editor_background, border_color: theme_color.border_variant, }; - if self.disabled { - style.text_color = theme_color.text_disabled; - style.background_color = theme_color.editor_background; - style.border_color = theme_color.border_disabled; - } - - // if self.error_message.is_some() { - // style.text_color = cx.theme().status().error; - // style.border_color = cx.theme().status().error_border - // } - - let text_style = TextStyle { - font_family: settings.ui_font.family.clone(), - font_features: settings.ui_font.features.clone(), - font_size: rems(0.875).into(), - font_weight: settings.buffer_font.weight, - font_style: FontStyle::Normal, - line_height: relative(1.2), - color: style.text_color, - ..Default::default() - }; - - let editor_style = EditorStyle { - background: theme_color.ghost_element_background, - local_player: cx.theme().players().local(), - syntax: cx.theme().syntax().clone(), - text: text_style, - ..Default::default() - }; - let focus_handle = self.editor.focus_handle(cx); let configured_handle = if let Some(tab_index) = self.tab_index { @@ -191,11 +147,7 @@ impl Render for InputField { this.child( Label::new(label) .size(self.label_size) - .color(if self.disabled { - Color::Disabled - } else { - Color::Default - }), + .color(Color::Default), ) }) .child( @@ -220,7 +172,7 @@ impl Render for InputField { this.gap_1() .child(Icon::new(icon).size(IconSize::Small).color(Color::Muted)) }) - .child(EditorElement::new(&self.editor, editor_style)), + .child(self.editor.render(window, cx)), ) } } diff --git a/crates/ui_input/src/ui_input.rs b/crates/ui_input/src/ui_input.rs index ddc0e659a2c34ffe53424bff24480c3f1b5875fb..769f24b32ea886980179430c6fd762ac7881322f 100644 --- a/crates/ui_input/src/ui_input.rs +++ b/crates/ui_input/src/ui_input.rs @@ -3,7 +3,39 @@ //! It can't be located in the `ui` crate because it depends on `editor`. //! mod input_field; -mod number_field; +use std::{ + any::Any, + sync::{Arc, OnceLock}, +}; + +use gpui::{FocusHandle, Subscription}; pub use input_field::*; -pub use number_field::*; +use ui::{AnyElement, App, Window}; + +pub trait ErasedEditor: 'static { + fn text(&self, cx: &App) -> String; + fn set_text(&self, text: &str, window: &mut Window, cx: &mut App); + fn clear(&self, window: &mut Window, cx: &mut App); + fn set_placeholder_text(&self, text: &str, window: &mut Window, _: &mut App); + fn move_selection_to_end(&self, window: &mut Window, _: &mut App); + + fn focus_handle(&self, cx: &App) -> FocusHandle; + + fn subscribe( + &self, + callback: Box, + window: &mut Window, + cx: &mut App, + ) -> Subscription; + fn render(&self, window: &mut Window, cx: &App) -> AnyElement; + fn as_any(&self) -> &dyn Any; +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ErasedEditorEvent { + BufferEdited, + Blurred, +} +pub static ERASED_EDITOR_FACTORY: OnceLock Arc> = + OnceLock::new(); diff --git a/crates/zed_actions/src/lib.rs b/crates/zed_actions/src/lib.rs index cf31756fa93e27fe1594d4c5098754b2db4c9434..1981b6f9422a38247c7a6755342565bdb5a29d4a 100644 --- a/crates/zed_actions/src/lib.rs +++ b/crates/zed_actions/src/lib.rs @@ -182,6 +182,19 @@ pub struct ResetAllZoom { pub persist: bool, } +pub mod editor { + use gpui::actions; + actions!( + editor, + [ + /// Moves cursor up. + MoveUp, + /// Moves cursor down. + MoveDown, + ] + ); +} + pub mod dev { use gpui::actions; @@ -340,6 +353,16 @@ pub mod icon_theme_selector { } } +pub mod search { + use gpui::actions; + actions!( + search, + [ + /// Toggles searching in ignored files. + ToggleIncludeIgnored + ] + ); +} pub mod settings_profile_selector { use gpui::Action; use schemars::JsonSchema;