Skip to main content

limit_cli/tools/browser/client_ext/
tabs.rs

1//! Tab operations
2
3use crate::tools::browser::executor::BrowserError;
4use crate::tools::browser::types::TabInfo;
5
6/// Tab operations for browser client
7pub trait TabsExt {
8    /// List all browser tabs
9    fn tab_list(
10        &self,
11    ) -> impl std::future::Future<Output = Result<Vec<TabInfo>, BrowserError>> + Send;
12
13    /// Open a new tab, optionally with URL
14    fn tab_new(
15        &self,
16        url: Option<&str>,
17    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
18
19    /// Close a tab by index (or current if None)
20    fn tab_close(
21        &self,
22        index: Option<usize>,
23    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
24
25    /// Select/switch to a tab by index
26    fn tab_select(
27        &self,
28        index: usize,
29    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
30
31    /// Accept a dialog (alert, confirm, prompt) with optional text
32    fn dialog_accept(
33        &self,
34        text: Option<&str>,
35    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
36
37    /// Dismiss a dialog (alert, confirm, prompt)
38    fn dialog_dismiss(&self) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
39}
40
41impl TabsExt for super::super::BrowserClient {
42    async fn tab_list(&self) -> Result<Vec<TabInfo>, BrowserError> {
43        let output = self.executor().execute(&["tab", "list"]).await?;
44
45        if output.success {
46            let tabs = output
47                .stdout
48                .lines()
49                .filter(|line| !line.is_empty())
50                .enumerate()
51                .map(|(i, line)| TabInfo {
52                    index: i,
53                    title: line.to_string(),
54                })
55                .collect();
56            Ok(tabs)
57        } else {
58            Err(BrowserError::Other(format!(
59                "Failed to list tabs: {}",
60                output.stderr
61            )))
62        }
63    }
64
65    async fn tab_new(&self, url: Option<&str>) -> Result<(), BrowserError> {
66        let output = if let Some(u) = url {
67            self.executor().execute(&["tab", "new", u]).await?
68        } else {
69            self.executor().execute(&["tab", "new"]).await?
70        };
71
72        if output.success {
73            Ok(())
74        } else {
75            Err(BrowserError::Other(format!(
76                "Failed to open new tab: {}",
77                output.stderr
78            )))
79        }
80    }
81
82    async fn tab_close(&self, index: Option<usize>) -> Result<(), BrowserError> {
83        let output = if let Some(i) = index {
84            let idx = i.to_string();
85            self.executor().execute(&["tab", "close", &idx]).await?
86        } else {
87            self.executor().execute(&["tab", "close"]).await?
88        };
89
90        if output.success {
91            Ok(())
92        } else {
93            Err(BrowserError::Other(format!(
94                "Failed to close tab: {}",
95                output.stderr
96            )))
97        }
98    }
99
100    async fn tab_select(&self, index: usize) -> Result<(), BrowserError> {
101        let idx = index.to_string();
102        let output = self.executor().execute(&["tab", "select", &idx]).await?;
103
104        if output.success {
105            Ok(())
106        } else {
107            Err(BrowserError::Other(format!(
108                "Failed to select tab: {}",
109                output.stderr
110            )))
111        }
112    }
113
114    async fn dialog_accept(&self, text: Option<&str>) -> Result<(), BrowserError> {
115        let output = if let Some(t) = text {
116            self.executor().execute(&["dialog", "accept", t]).await?
117        } else {
118            self.executor().execute(&["dialog", "accept"]).await?
119        };
120
121        if output.success {
122            Ok(())
123        } else {
124            Err(BrowserError::Other(format!(
125                "Failed to accept dialog: {}",
126                output.stderr
127            )))
128        }
129    }
130
131    async fn dialog_dismiss(&self) -> Result<(), BrowserError> {
132        let output = self.executor().execute(&["dialog", "dismiss"]).await?;
133
134        if output.success {
135            Ok(())
136        } else {
137            Err(BrowserError::Other(format!(
138                "Failed to dismiss dialog: {}",
139                output.stderr
140            )))
141        }
142    }
143}