Select tabs from command scope
This commit is contained in:
@@ -32,8 +32,14 @@ impl ElyShell {
|
||||
let command_input =
|
||||
cx.new(|cx| InputState::new(window, cx).placeholder("Search or enter address"));
|
||||
|
||||
let command_subscription =
|
||||
cx.subscribe(&command_input, |shell: &mut Self, input, event: &InputEvent, cx| {
|
||||
let command_subscription = cx.subscribe_in(
|
||||
&command_input,
|
||||
window,
|
||||
|shell: &mut Self, input, event: &InputEvent, window, cx| {
|
||||
let mut submitted_intent = None;
|
||||
let mut sync_address = false;
|
||||
let submitted = matches!(event, InputEvent::PressEnter { .. });
|
||||
|
||||
let ShellState::Ready(core) = &mut shell.state else {
|
||||
return;
|
||||
};
|
||||
@@ -41,12 +47,22 @@ impl ElyShell {
|
||||
let value = input.read(cx).value().to_string();
|
||||
core.set_command_query(value);
|
||||
|
||||
if matches!(event, InputEvent::PressEnter { .. }) {
|
||||
shell.last_intent = core.submit_command().ok().flatten();
|
||||
if submitted {
|
||||
submitted_intent = core.submit_command().ok().flatten();
|
||||
sync_address = core.command_query().is_empty();
|
||||
}
|
||||
|
||||
if submitted {
|
||||
shell.last_intent = submitted_intent;
|
||||
}
|
||||
|
||||
if sync_address {
|
||||
shell.sync_address_input(window, cx);
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let state = match InitialBrowserConfig::ely_defaults().and_then(|config| {
|
||||
BrowserCore::new(config).map_err(|error| match error {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use ely_domain::{
|
||||
BrowserTab, CommandIntent, DomainError, Profile, ProfileId, ProfileKind, Space, SpaceId, TabId,
|
||||
UrlText,
|
||||
BrowserTab, CommandIntent, CommandScope, DomainError, Profile, ProfileId, ProfileKind, Space,
|
||||
SpaceId, TabId, UrlText,
|
||||
};
|
||||
|
||||
use crate::CoreError;
|
||||
@@ -140,6 +140,11 @@ impl BrowserCore {
|
||||
self.command_query = query.into();
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn command_query(&self) -> &str {
|
||||
&self.command_query
|
||||
}
|
||||
|
||||
pub fn submit_command(&mut self) -> Result<Option<CommandIntent>, CoreError> {
|
||||
let query = self.command_query.trim();
|
||||
if query.is_empty() {
|
||||
@@ -147,10 +152,19 @@ impl BrowserCore {
|
||||
}
|
||||
|
||||
let intent = CommandIntent::parse(query)?;
|
||||
if let CommandIntent::Navigate(url) = &intent {
|
||||
match &intent {
|
||||
CommandIntent::Navigate(url) => {
|
||||
self.open_tab(url.clone());
|
||||
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)?;
|
||||
self.command_query.clear();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(Some(intent))
|
||||
}
|
||||
@@ -199,6 +213,14 @@ impl BrowserCore {
|
||||
.ok_or(CoreError::MissingActiveTab)
|
||||
}
|
||||
|
||||
fn find_tab_match(&self, query: &str) -> Option<TabId> {
|
||||
let normalized_query = query.trim().to_lowercase();
|
||||
self.tabs
|
||||
.iter()
|
||||
.find(|tab| tab_matches_query(tab, &normalized_query))
|
||||
.map(|tab| tab.id().clone())
|
||||
}
|
||||
|
||||
fn build_tab(&self, url: UrlText) -> BrowserTab {
|
||||
let title = tab_title(&url);
|
||||
BrowserTab::new(
|
||||
@@ -219,11 +241,17 @@ fn tab_title(url: &UrlText) -> String {
|
||||
url.display_host()
|
||||
}
|
||||
|
||||
fn tab_matches_query(tab: &BrowserTab, normalized_query: &str) -> bool {
|
||||
tab.title().to_lowercase().contains(normalized_query)
|
||||
|| tab.url().as_str().to_lowercase().contains(normalized_query)
|
||||
|| tab.display_url().to_lowercase().contains(normalized_query)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::error::Error;
|
||||
|
||||
use ely_domain::UrlText;
|
||||
use ely_domain::{CommandIntent, CommandScope, UrlText};
|
||||
|
||||
use super::{BrowserCore, InitialBrowserConfig};
|
||||
use crate::CoreError;
|
||||
@@ -311,4 +339,39 @@ mod tests {
|
||||
assert_eq!(wrapped_tab_id, third_tab_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_scoped_search_selects_matching_open_tab() -> Result<(), Box<dyn Error>> {
|
||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||
let first_tab_id = core.active_tab()?.id().clone();
|
||||
core.open_tab(UrlText::parse("https://example.com")?);
|
||||
let servo_tab_id = core.open_tab(UrlText::parse("https://servo.org")?);
|
||||
|
||||
core.select_tab(&first_tab_id)?;
|
||||
core.set_command_query("@tabs servo");
|
||||
let intent = core.submit_command()?;
|
||||
|
||||
let snapshot = core.snapshot()?;
|
||||
assert!(matches!(
|
||||
intent,
|
||||
Some(CommandIntent::ScopedSearch { scope: CommandScope::Tabs, query }) if query == "servo"
|
||||
));
|
||||
assert_eq!(snapshot.active_tab_id, servo_tab_id);
|
||||
assert_eq!(snapshot.command_query, "");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_scoped_search_preserves_query_without_match() -> Result<(), Box<dyn Error>> {
|
||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||
let active_tab_id = core.active_tab()?.id().clone();
|
||||
|
||||
core.set_command_query("@tabs absent");
|
||||
core.submit_command()?;
|
||||
|
||||
let snapshot = core.snapshot()?;
|
||||
assert_eq!(snapshot.active_tab_id, active_tab_id);
|
||||
assert_eq!(snapshot.command_query, "@tabs absent");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user