From 1020fa871b0d394d936b2e51be9b2dc607663abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 7 May 2026 19:20:12 -0400 Subject: [PATCH] Open searches from command bar --- Cargo.lock | 1 + crates/ely_browser_core/Cargo.toml | 1 + crates/ely_browser_core/src/state.rs | 29 ++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8bc7138..a9b10c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2209,6 +2209,7 @@ version = "0.1.0" dependencies = [ "ely_domain", "thiserror 2.0.18", + "url", ] [[package]] diff --git a/crates/ely_browser_core/Cargo.toml b/crates/ely_browser_core/Cargo.toml index 0b18c3e..07d8b25 100644 --- a/crates/ely_browser_core/Cargo.toml +++ b/crates/ely_browser_core/Cargo.toml @@ -8,6 +8,7 @@ rust-version.workspace = true [dependencies] ely_domain = { path = "../ely_domain" } thiserror.workspace = true +url.workspace = true [lints] workspace = true diff --git a/crates/ely_browser_core/src/state.rs b/crates/ely_browser_core/src/state.rs index 1f1b5c0..a60af1a 100644 --- a/crates/ely_browser_core/src/state.rs +++ b/crates/ely_browser_core/src/state.rs @@ -2,9 +2,12 @@ use ely_domain::{ BrowserTab, CommandIntent, CommandScope, DomainError, Profile, ProfileId, ProfileKind, Space, SpaceId, TabId, UrlText, }; +use url::Url; use crate::CoreError; +const DEFAULT_SEARCH_URL: &str = "https://duckduckgo.com/"; + #[derive(Clone, Debug)] pub struct InitialBrowserConfig { pub space_name: String, @@ -157,6 +160,11 @@ impl BrowserCore { self.open_tab(url.clone()); self.command_query.clear(); } + CommandIntent::Search(query) => { + let url = search_url(query)?; + self.open_tab(url); + self.command_query.clear(); + } CommandIntent::ScopedSearch { scope: CommandScope::Tabs, query } => { if let Some(tab_id) = self.find_tab_match(query) { self.select_tab(&tab_id)?; @@ -247,6 +255,13 @@ fn tab_matches_query(tab: &BrowserTab, normalized_query: &str) -> bool { || tab.display_url().to_lowercase().contains(normalized_query) } +fn search_url(query: &str) -> Result { + let mut url = Url::parse(DEFAULT_SEARCH_URL) + .map_err(|_| DomainError::InvalidUrl { value: DEFAULT_SEARCH_URL.to_string() })?; + url.query_pairs_mut().append_pair("q", query); + UrlText::parse(url.to_string()).map_err(CoreError::from) +} + #[cfg(test)] mod tests { use std::error::Error; @@ -374,4 +389,18 @@ mod tests { assert_eq!(snapshot.command_query, "@tabs absent"); Ok(()) } + + #[test] + fn search_command_opens_default_search_url() -> Result<(), Box> { + let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; + + core.set_command_query("? rust async book"); + let intent = core.submit_command()?; + + let active_tab = core.active_tab()?; + assert_eq!(intent, Some(CommandIntent::Search("rust async book".to_string()))); + assert_eq!(active_tab.url().as_str(), "https://duckduckgo.com/?q=rust+async+book"); + assert_eq!(core.command_query(), ""); + Ok(()) + } }