Skip to main content

vibe_workspace/uri/
handler.rs

1use anyhow::Result;
2use async_trait::async_trait;
3use std::sync::Arc;
4
5use crate::git::{CloneCommand, GitConfig, SearchCommand};
6use crate::uri::{parse_vibe_uri, VibeUri};
7use crate::workspace::manager::WorkspaceManager;
8
9#[async_trait]
10pub trait UriHandler: Send + Sync {
11    fn can_handle(&self, uri: &VibeUri) -> bool;
12    async fn handle(&self, uri: &VibeUri) -> Result<()>;
13}
14
15pub struct UriRouter {
16    handlers: Vec<Box<dyn UriHandler>>,
17}
18
19impl UriRouter {
20    pub fn new() -> Self {
21        Self {
22            handlers: Vec::new(),
23        }
24    }
25
26    pub fn add_handler(&mut self, handler: Box<dyn UriHandler>) {
27        self.handlers.push(handler);
28    }
29
30    pub async fn handle_uri(&self, uri_str: &str) -> Result<()> {
31        let uri = parse_vibe_uri(uri_str)?;
32
33        for handler in &self.handlers {
34            if handler.can_handle(&uri) {
35                return handler.handle(&uri).await;
36            }
37        }
38
39        anyhow::bail!("No handler found for URI: {}", uri_str)
40    }
41}
42
43// GitHub URI Handler
44pub struct GitHubUriHandler {
45    workspace_manager: Arc<tokio::sync::Mutex<WorkspaceManager>>,
46    git_config: GitConfig,
47}
48
49impl GitHubUriHandler {
50    pub fn new(
51        workspace_manager: Arc<tokio::sync::Mutex<WorkspaceManager>>,
52        git_config: GitConfig,
53    ) -> Self {
54        Self {
55            workspace_manager,
56            git_config,
57        }
58    }
59}
60
61#[async_trait]
62impl UriHandler for GitHubUriHandler {
63    fn can_handle(&self, uri: &VibeUri) -> bool {
64        uri.action == "github"
65    }
66
67    async fn handle(&self, uri: &VibeUri) -> Result<()> {
68        match uri.command.as_str() {
69            "install" => {
70                if let Some(path) = uri.params.get("path") {
71                    let url = format!("https://github.com/{path}");
72                    let mut manager = self.workspace_manager.lock().await;
73                    CloneCommand::execute(url, None, false, false, &mut manager, &self.git_config)
74                        .await?;
75                } else {
76                    anyhow::bail!("Missing repository path in URI");
77                }
78            }
79            "search" => {
80                // For URI-based search, we'll just open the interactive search
81                let mut manager = self.workspace_manager.lock().await;
82                SearchCommand::execute_interactive(&mut manager, &self.git_config).await?;
83            }
84            _ => anyhow::bail!("Unknown GitHub command: {}", uri.command),
85        }
86
87        Ok(())
88    }
89}
90
91// Platform-specific URI registration
92pub fn register_uri_scheme(scheme: &str) -> Result<()> {
93    #[cfg(target_os = "macos")]
94    {
95        macos::register_uri_scheme(scheme)
96    }
97
98    #[cfg(target_os = "linux")]
99    {
100        linux::register_uri_scheme(scheme)
101    }
102
103    #[cfg(target_os = "windows")]
104    {
105        windows::register_uri_scheme(scheme)
106    }
107
108    #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
109    {
110        anyhow::bail!("URI scheme registration not supported on this platform")
111    }
112}
113
114// macOS implementation
115#[cfg(target_os = "macos")]
116mod macos {
117    use anyhow::Result;
118
119    pub fn register_uri_scheme(scheme: &str) -> Result<()> {
120        // For macOS, we need to update the Info.plist of the application
121        // This is typically done during the build/install process
122        // For now, we'll provide instructions
123
124        eprintln!("To register the '{scheme}' URI scheme on macOS:");
125        eprintln!("1. Add the following to your Info.plist:");
126        eprintln!("   <key>CFBundleURLTypes</key>");
127        eprintln!("   <array>");
128        eprintln!("     <dict>");
129        eprintln!("       <key>CFBundleURLSchemes</key>");
130        eprintln!("       <array>");
131        eprintln!("         <string>{scheme}</string>");
132        eprintln!("       </array>");
133        eprintln!("     </dict>");
134        eprintln!("   </array>");
135        eprintln!("2. Rebuild and reinstall the application");
136
137        Ok(())
138    }
139}
140
141// Linux implementation (stub)
142#[cfg(target_os = "linux")]
143mod linux {
144    use anyhow::Result;
145
146    pub fn register_uri_scheme(scheme: &str) -> Result<()> {
147        // Linux implementation would create a .desktop file
148        eprintln!(
149            "Linux URI scheme registration not yet implemented for '{}'",
150            scheme
151        );
152        Ok(())
153    }
154}
155
156// Windows implementation (stub)
157#[cfg(target_os = "windows")]
158mod windows {
159    use anyhow::Result;
160
161    pub fn register_uri_scheme(scheme: &str) -> Result<()> {
162        // Windows implementation would modify the registry
163        eprintln!(
164            "Windows URI scheme registration not yet implemented for '{}'",
165            scheme
166        );
167        Ok(())
168    }
169}