Restore archived tabs from command scope

This commit is contained in:
2026-05-07 19:59:55 -04:00
parent e0eb5b51b2
commit 75e17fc70f
4 changed files with 107 additions and 0 deletions
+28
View File
@@ -128,6 +128,29 @@ impl BrowserCore {
pub fn restore_last_archived_tab(&mut self) -> Result<TabId, CoreError> { pub fn restore_last_archived_tab(&mut self) -> Result<TabId, CoreError> {
let archived_tab = self.archived_tabs.pop().ok_or(CoreError::NoArchivedTabs)?; let archived_tab = self.archived_tabs.pop().ok_or(CoreError::NoArchivedTabs)?;
let tab = archived_tab.into_tab(); let tab = archived_tab.into_tab();
self.restore_tab(tab)
}
pub fn restore_archived_tab_match(&mut self, query: &str) -> Result<Option<TabId>, CoreError> {
let normalized_query = query.trim().to_lowercase();
if normalized_query.is_empty() {
return Ok(None);
}
let Some(index) = self
.archived_tabs
.iter()
.rposition(|archived| tab_matches_query(archived.tab(), &normalized_query))
else {
return Ok(None);
};
let archived_tab = self.archived_tabs.remove(index);
let tab = archived_tab.into_tab();
self.restore_tab(tab).map(Some)
}
fn restore_tab(&mut self, tab: BrowserTab) -> Result<TabId, CoreError> {
let tab_id = tab.id().clone(); let tab_id = tab.id().clone();
let insert_index = self let insert_index = self
.tabs .tabs
@@ -219,6 +242,11 @@ impl BrowserCore {
self.command_query.clear(); self.command_query.clear();
} }
} }
CommandIntent::ScopedSearch { scope: CommandScope::Archive, query }
if self.restore_archived_tab_match(query)?.is_some() =>
{
self.command_query.clear();
}
_ => {} _ => {}
} }
+41
View File
@@ -84,6 +84,47 @@ fn restore_tab_command_reopens_last_archived_tab() -> Result<(), Box<dyn Error>>
Ok(()) Ok(())
} }
#[test]
fn archive_scoped_search_restores_matching_archived_tab() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
core.open_tab(UrlText::parse("https://example.com")?);
let servo_tab_id = core.open_tab(UrlText::parse("https://servo.org")?);
core.close_active_tab()?;
core.set_command_query("@archive servo");
let intent = core.submit_command()?;
let snapshot = core.snapshot()?;
assert_eq!(
intent,
Some(CommandIntent::ScopedSearch {
scope: ely_domain::CommandScope::Archive,
query: "servo".to_string()
})
);
assert_eq!(snapshot.active_tab_id, servo_tab_id);
assert!(snapshot.archived_tabs.is_empty());
assert_eq!(snapshot.command_query, "");
Ok(())
}
#[test]
fn archive_scoped_search_preserves_query_without_match() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
core.open_tab(UrlText::parse("https://example.com")?);
core.close_active_tab()?;
let active_tab_id = core.active_tab()?.id().clone();
core.set_command_query("@archive absent");
core.submit_command()?;
let snapshot = core.snapshot()?;
assert_eq!(snapshot.active_tab_id, active_tab_id);
assert_eq!(snapshot.archived_tabs.len(), 1);
assert_eq!(snapshot.command_query, "@archive absent");
Ok(())
}
#[test] #[test]
fn unknown_command_preserves_query() -> Result<(), Box<dyn Error>> { fn unknown_command_preserves_query() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
+36
View File
@@ -73,6 +73,42 @@ fn restores_last_archived_tab() -> Result<(), Box<dyn Error>> {
Ok(()) Ok(())
} }
#[test]
fn restores_matching_archived_tab() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let example_tab_id = core.open_tab(UrlText::parse("https://example.com")?);
let servo_tab_id = core.open_tab(UrlText::parse("https://servo.org")?);
core.close_active_tab()?;
core.select_tab(&example_tab_id)?;
core.close_active_tab()?;
let restored_tab_id = core.restore_archived_tab_match("servo")?;
let snapshot = core.snapshot()?;
assert_eq!(restored_tab_id, Some(servo_tab_id.clone()));
assert_eq!(snapshot.active_tab_id, servo_tab_id);
assert_eq!(snapshot.archived_tabs.len(), 1);
assert_eq!(snapshot.archived_tabs[0].tab().id(), &example_tab_id);
Ok(())
}
#[test]
fn ignores_empty_archived_tab_match_query() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
core.open_tab(UrlText::parse("https://example.com")?);
core.close_active_tab()?;
let active_tab_id = core.active_tab()?.id().clone();
let restored_tab_id = core.restore_archived_tab_match(" ")?;
let snapshot = core.snapshot()?;
assert_eq!(restored_tab_id, None);
assert_eq!(snapshot.active_tab_id, active_tab_id);
assert_eq!(snapshot.archived_tabs.len(), 1);
Ok(())
}
#[test] #[test]
fn restore_without_archived_tabs_returns_error() -> Result<(), Box<dyn Error>> { fn restore_without_archived_tabs_returns_error() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
+2
View File
@@ -2,6 +2,7 @@ use crate::{DomainError, UrlText};
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum CommandScope { pub enum CommandScope {
Archive,
Tabs, Tabs,
Bookmarks, Bookmarks,
History, History,
@@ -43,6 +44,7 @@ impl CommandIntent {
fn parse_scope(value: &str) -> Option<(CommandScope, &str)> { fn parse_scope(value: &str) -> Option<(CommandScope, &str)> {
let (scope, query) = value.split_once(' ')?; let (scope, query) = value.split_once(' ')?;
let scope = match scope { let scope = match scope {
"@archive" => CommandScope::Archive,
"@tabs" => CommandScope::Tabs, "@tabs" => CommandScope::Tabs,
"@bookmarks" => CommandScope::Bookmarks, "@bookmarks" => CommandScope::Bookmarks,
"@history" => CommandScope::History, "@history" => CommandScope::History,