mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Code to allow opening zed:/channel/1234
Refactored a bit how url arguments are handled to avoid adding too much extra complexity to main.
This commit is contained in:
parent
b258ee5f77
commit
13192fa03c
@ -182,6 +182,7 @@ impl Bundle {
|
|||||||
kCFStringEncodingUTF8,
|
kCFStringEncodingUTF8,
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
));
|
));
|
||||||
|
// equivalent to: open zed-cli:... -a /Applications/Zed\ Preview.app
|
||||||
let urls_to_open = CFArray::from_copyable(&[url_to_open.as_concrete_TypeRef()]);
|
let urls_to_open = CFArray::from_copyable(&[url_to_open.as_concrete_TypeRef()]);
|
||||||
LSOpenFromURLSpec(
|
LSOpenFromURLSpec(
|
||||||
&LSLaunchURLSpec {
|
&LSLaunchURLSpec {
|
||||||
|
@ -1969,18 +1969,21 @@ impl CollabPanel {
|
|||||||
let style = collab_theme.channel_name.inactive_state();
|
let style = collab_theme.channel_name.inactive_state();
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_child(
|
.with_child(
|
||||||
Label::new(channel.name.clone(), style.text.clone())
|
Label::new(
|
||||||
.contained()
|
channel.name.clone().to_owned() + channel_id.to_string().as_str(),
|
||||||
.with_style(style.container)
|
style.text.clone(),
|
||||||
.aligned()
|
)
|
||||||
.left()
|
.contained()
|
||||||
.with_tooltip::<ChannelTooltip>(
|
.with_style(style.container)
|
||||||
ix,
|
.aligned()
|
||||||
"Join channel",
|
.left()
|
||||||
None,
|
.with_tooltip::<ChannelTooltip>(
|
||||||
theme.tooltip.clone(),
|
ix,
|
||||||
cx,
|
"Join channel",
|
||||||
),
|
None,
|
||||||
|
theme.tooltip.clone(),
|
||||||
|
cx,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.with_children({
|
.with_children({
|
||||||
let participants =
|
let participants =
|
||||||
@ -3187,49 +3190,19 @@ impl CollabPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn join_channel(&self, channel_id: u64, cx: &mut ViewContext<Self>) {
|
fn join_channel(&self, channel_id: u64, cx: &mut ViewContext<Self>) {
|
||||||
let workspace = self.workspace.clone();
|
let Some(workspace) = self.workspace.upgrade(cx) else {
|
||||||
let window = cx.window();
|
return;
|
||||||
let active_call = ActiveCall::global(cx);
|
};
|
||||||
cx.spawn(|_, mut cx| async move {
|
let Some(handle) = cx.window().downcast::<Workspace>() else {
|
||||||
if active_call.read_with(&mut cx, |active_call, cx| {
|
return;
|
||||||
if let Some(room) = active_call.room() {
|
};
|
||||||
let room = room.read(cx);
|
workspace::join_channel(
|
||||||
room.is_sharing_project() && room.remote_participants().len() > 0
|
channel_id,
|
||||||
} else {
|
workspace.read(cx).app_state().clone(),
|
||||||
false
|
Some(handle),
|
||||||
}
|
cx,
|
||||||
}) {
|
)
|
||||||
let answer = window.prompt(
|
.detach_and_log_err(cx)
|
||||||
PromptLevel::Warning,
|
|
||||||
"Leaving this call will unshare your current project.\nDo you want to switch channels?",
|
|
||||||
&["Yes, Join Channel", "Cancel"],
|
|
||||||
&mut cx,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(mut answer) = answer {
|
|
||||||
if answer.next().await == Some(1) {
|
|
||||||
return anyhow::Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let room = active_call
|
|
||||||
.update(&mut cx, |call, cx| call.join_channel(channel_id, cx))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let task = room.update(&mut cx, |room, cx| {
|
|
||||||
let workspace = workspace.upgrade(cx)?;
|
|
||||||
let (project, host) = room.most_active_project()?;
|
|
||||||
let app_state = workspace.read(cx).app_state().clone();
|
|
||||||
Some(workspace::join_remote_project(project, host, app_state, cx))
|
|
||||||
});
|
|
||||||
if let Some(task) = task {
|
|
||||||
task.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
|
||||||
.detach_and_log_err(cx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn join_channel_chat(&mut self, action: &JoinChannelChat, cx: &mut ViewContext<Self>) {
|
fn join_channel_chat(&mut self, action: &JoinChannelChat, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -17,15 +17,14 @@ lazy_static! {
|
|||||||
_ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME),
|
_ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME),
|
||||||
};
|
};
|
||||||
|
|
||||||
static ref URL_SCHEME: Url = Url::parse(match RELEASE_CHANNEL_NAME.as_str() {
|
pub static ref URL_SCHEME_PREFIX: String = match RELEASE_CHANNEL_NAME.as_str() {
|
||||||
"dev" => "zed-dev:/",
|
"dev" => "zed-dev:/",
|
||||||
"preview" => "zed-preview:/",
|
"preview" => "zed-preview:/",
|
||||||
"stable" => "zed:/",
|
"stable" => "zed:/",
|
||||||
// NOTE: this must be kept in sync with ./script/bundle and https://zed.dev.
|
// NOTE: this must be kept in sync with osx_url_schemes in Cargo.toml and with https://zed.dev.
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
}.to_string();
|
||||||
.unwrap();
|
pub static ref LINK_PREFIX: Url = Url::parse(match RELEASE_CHANNEL_NAME.as_str() {
|
||||||
static ref LINK_PREFIX: Url = Url::parse(match RELEASE_CHANNEL_NAME.as_str() {
|
|
||||||
"dev" => "http://localhost:3000/dev/",
|
"dev" => "http://localhost:3000/dev/",
|
||||||
"preview" => "https://zed.dev/preview/",
|
"preview" => "https://zed.dev/preview/",
|
||||||
"stable" => "https://zed.dev/",
|
"stable" => "https://zed.dev/",
|
||||||
@ -59,12 +58,4 @@ impl ReleaseChannel {
|
|||||||
ReleaseChannel::Stable => "stable",
|
ReleaseChannel::Stable => "stable",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url_scheme(&self) -> &'static Url {
|
|
||||||
&URL_SCHEME
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn link_prefix(&self) -> &'static Url {
|
|
||||||
&LINK_PREFIX
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4154,6 +4154,88 @@ pub async fn last_opened_workspace_paths() -> Option<WorkspaceLocation> {
|
|||||||
DB.last_workspace().await.log_err().flatten()
|
DB.last_workspace().await.log_err().flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn join_channel(
|
||||||
|
channel_id: u64,
|
||||||
|
app_state: Arc<AppState>,
|
||||||
|
requesting_window: Option<WindowHandle<Workspace>>,
|
||||||
|
cx: &mut AppContext,
|
||||||
|
) -> Task<Result<()>> {
|
||||||
|
let active_call = ActiveCall::global(cx);
|
||||||
|
cx.spawn(|mut cx| async move {
|
||||||
|
let should_prompt = active_call.read_with(&mut cx, |active_call, cx| {
|
||||||
|
let Some(room) = active_call.room().map( |room| room.read(cx) ) else {
|
||||||
|
return false
|
||||||
|
};
|
||||||
|
|
||||||
|
room.is_sharing_project() && room.remote_participants().len() > 0 &&
|
||||||
|
room.channel_id() != Some(channel_id)
|
||||||
|
});
|
||||||
|
|
||||||
|
if should_prompt {
|
||||||
|
if let Some(workspace) = requesting_window {
|
||||||
|
if let Some(window) = workspace.update(&mut cx, |cx| {
|
||||||
|
cx.window()
|
||||||
|
}) {
|
||||||
|
let answer = window.prompt(
|
||||||
|
PromptLevel::Warning,
|
||||||
|
"Leaving this call will unshare your current project.\nDo you want to switch channels?",
|
||||||
|
&["Yes, Join Channel", "Cancel"],
|
||||||
|
&mut cx,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(mut answer) = answer {
|
||||||
|
if answer.next().await == Some(1) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let room = active_call.update(&mut cx, |active_call, cx| {
|
||||||
|
active_call.join_channel(channel_id, cx)
|
||||||
|
}).await?;
|
||||||
|
|
||||||
|
let task = room.update(&mut cx, |room, cx| {
|
||||||
|
if let Some((project, host)) = room.most_active_project() {
|
||||||
|
return Some(join_remote_project(project, host, app_state.clone(), cx))
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
});
|
||||||
|
if let Some(task) = task {
|
||||||
|
task.await?;
|
||||||
|
return anyhow::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if requesting_window.is_some() {
|
||||||
|
return anyhow::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// find an existing workspace to focus and show call controls
|
||||||
|
for window in cx.windows() {
|
||||||
|
let found = window.update(&mut cx, |cx| {
|
||||||
|
let is_workspace = cx.root_view().clone().downcast::<Workspace>().is_some();
|
||||||
|
if is_workspace {
|
||||||
|
cx.activate_window();
|
||||||
|
}
|
||||||
|
is_workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
if found.unwrap_or(false) {
|
||||||
|
return anyhow::Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no open workspaces
|
||||||
|
cx.update(|cx| {
|
||||||
|
Workspace::new_local(vec![], app_state.clone(), requesting_window, cx)
|
||||||
|
}).await;
|
||||||
|
|
||||||
|
return anyhow::Ok(());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn open_paths(
|
pub fn open_paths(
|
||||||
abs_paths: &[PathBuf],
|
abs_paths: &[PathBuf],
|
||||||
|
@ -45,7 +45,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
use sum_tree::Bias;
|
use sum_tree::Bias;
|
||||||
use util::{
|
use util::{
|
||||||
channel::ReleaseChannel,
|
channel::{ReleaseChannel, URL_SCHEME_PREFIX},
|
||||||
http::{self, HttpClient},
|
http::{self, HttpClient},
|
||||||
paths::PathLikeWithPosition,
|
paths::PathLikeWithPosition,
|
||||||
};
|
};
|
||||||
@ -61,6 +61,10 @@ use zed::{
|
|||||||
only_instance::{ensure_only_instance, IsOnlyInstance},
|
only_instance::{ensure_only_instance, IsOnlyInstance},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::open_url::{OpenListener, OpenRequest};
|
||||||
|
|
||||||
|
mod open_url;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let http = http::client();
|
let http = http::client();
|
||||||
init_paths();
|
init_paths();
|
||||||
@ -92,29 +96,20 @@ fn main() {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let (cli_connections_tx, mut cli_connections_rx) = mpsc::unbounded();
|
let (listener, mut open_rx) = OpenListener::new();
|
||||||
let cli_connections_tx = Arc::new(cli_connections_tx);
|
let listener = Arc::new(listener);
|
||||||
let (open_paths_tx, mut open_paths_rx) = mpsc::unbounded();
|
let callback_listener = listener.clone();
|
||||||
let open_paths_tx = Arc::new(open_paths_tx);
|
app.on_open_urls(move |urls, _| callback_listener.open_urls(urls))
|
||||||
let urls_callback_triggered = Arc::new(AtomicBool::new(false));
|
.on_reopen(move |cx| {
|
||||||
|
if cx.has_global::<Weak<AppState>>() {
|
||||||
let callback_cli_connections_tx = Arc::clone(&cli_connections_tx);
|
if let Some(app_state) = cx.global::<Weak<AppState>>().upgrade() {
|
||||||
let callback_open_paths_tx = Arc::clone(&open_paths_tx);
|
workspace::open_new(&app_state, cx, |workspace, cx| {
|
||||||
let callback_urls_callback_triggered = Arc::clone(&urls_callback_triggered);
|
Editor::new_file(workspace, &Default::default(), cx)
|
||||||
app.on_open_urls(move |urls, _| {
|
})
|
||||||
callback_urls_callback_triggered.store(true, Ordering::Release);
|
.detach();
|
||||||
open_urls(urls, &callback_cli_connections_tx, &callback_open_paths_tx);
|
}
|
||||||
})
|
|
||||||
.on_reopen(move |cx| {
|
|
||||||
if cx.has_global::<Weak<AppState>>() {
|
|
||||||
if let Some(app_state) = cx.global::<Weak<AppState>>().upgrade() {
|
|
||||||
workspace::open_new(&app_state, cx, |workspace, cx| {
|
|
||||||
Editor::new_file(workspace, &Default::default(), cx)
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
app.run(move |cx| {
|
app.run(move |cx| {
|
||||||
cx.set_global(*RELEASE_CHANNEL);
|
cx.set_global(*RELEASE_CHANNEL);
|
||||||
@ -226,41 +221,52 @@ fn main() {
|
|||||||
// TODO Development mode that forces the CLI mode usually runs Zed binary as is instead
|
// TODO Development mode that forces the CLI mode usually runs Zed binary as is instead
|
||||||
// of an *app, hence gets no specific callbacks run. Emulate them here, if needed.
|
// of an *app, hence gets no specific callbacks run. Emulate them here, if needed.
|
||||||
if std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_some()
|
if std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_some()
|
||||||
&& !urls_callback_triggered.load(Ordering::Acquire)
|
&& !listener.triggered.load(Ordering::Acquire)
|
||||||
{
|
{
|
||||||
open_urls(collect_url_args(), &cli_connections_tx, &open_paths_tx)
|
listener.open_urls(collect_url_args())
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(Some(connection)) = cli_connections_rx.try_next() {
|
match open_rx.try_next() {
|
||||||
cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx))
|
Ok(Some(OpenRequest::Paths { paths })) => {
|
||||||
.detach();
|
cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx))
|
||||||
} else if let Ok(Some(paths)) = open_paths_rx.try_next() {
|
.detach();
|
||||||
cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx))
|
|
||||||
.detach();
|
|
||||||
} else {
|
|
||||||
cx.spawn({
|
|
||||||
let app_state = app_state.clone();
|
|
||||||
|cx| async move { restore_or_create_workspace(&app_state, cx).await }
|
|
||||||
})
|
|
||||||
.detach()
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.spawn(|cx| {
|
|
||||||
let app_state = app_state.clone();
|
|
||||||
async move {
|
|
||||||
while let Some(connection) = cli_connections_rx.next().await {
|
|
||||||
handle_cli_connection(connection, app_state.clone(), cx.clone()).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
Ok(Some(OpenRequest::CliConnection { connection })) => {
|
||||||
.detach();
|
cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx))
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
Ok(Some(OpenRequest::JoinChannel { channel_id })) => cx
|
||||||
|
.update(|cx| workspace::join_channel(channel_id, app_state.clone(), None, cx))
|
||||||
|
.detach(),
|
||||||
|
Ok(None) | Err(_) => cx
|
||||||
|
.spawn({
|
||||||
|
let app_state = app_state.clone();
|
||||||
|
|cx| async move { restore_or_create_workspace(&app_state, cx).await }
|
||||||
|
})
|
||||||
|
.detach(),
|
||||||
|
}
|
||||||
|
|
||||||
cx.spawn(|mut cx| {
|
cx.spawn(|mut cx| {
|
||||||
let app_state = app_state.clone();
|
let app_state = app_state.clone();
|
||||||
async move {
|
async move {
|
||||||
while let Some(paths) = open_paths_rx.next().await {
|
while let Some(request) = open_rx.next().await {
|
||||||
cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx))
|
match request {
|
||||||
.detach();
|
OpenRequest::Paths { paths } => {
|
||||||
|
cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx))
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
OpenRequest::CliConnection { connection } => {
|
||||||
|
cx.spawn(|cx| {
|
||||||
|
handle_cli_connection(connection, app_state.clone(), cx)
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
OpenRequest::JoinChannel { channel_id } => cx
|
||||||
|
.update(|cx| {
|
||||||
|
workspace::join_channel(channel_id, app_state.clone(), None, cx)
|
||||||
|
})
|
||||||
|
.detach(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -297,37 +303,6 @@ async fn installation_id() -> Result<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_urls(
|
|
||||||
urls: Vec<String>,
|
|
||||||
cli_connections_tx: &mpsc::UnboundedSender<(
|
|
||||||
mpsc::Receiver<CliRequest>,
|
|
||||||
IpcSender<CliResponse>,
|
|
||||||
)>,
|
|
||||||
open_paths_tx: &mpsc::UnboundedSender<Vec<PathBuf>>,
|
|
||||||
) {
|
|
||||||
if let Some(server_name) = urls.first().and_then(|url| url.strip_prefix("zed-cli://")) {
|
|
||||||
if let Some(cli_connection) = connect_to_cli(server_name).log_err() {
|
|
||||||
cli_connections_tx
|
|
||||||
.unbounded_send(cli_connection)
|
|
||||||
.map_err(|_| anyhow!("no listener for cli connections"))
|
|
||||||
.log_err();
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
let paths: Vec<_> = urls
|
|
||||||
.iter()
|
|
||||||
.flat_map(|url| url.strip_prefix("file://"))
|
|
||||||
.map(|url| {
|
|
||||||
let decoded = urlencoding::decode_binary(url.as_bytes());
|
|
||||||
PathBuf::from(OsStr::from_bytes(decoded.as_ref()))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
open_paths_tx
|
|
||||||
.unbounded_send(paths)
|
|
||||||
.map_err(|_| anyhow!("no listener for open urls requests"))
|
|
||||||
.log_err();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn restore_or_create_workspace(app_state: &Arc<AppState>, mut cx: AsyncAppContext) {
|
async fn restore_or_create_workspace(app_state: &Arc<AppState>, mut cx: AsyncAppContext) {
|
||||||
if let Some(location) = workspace::last_opened_workspace_paths().await {
|
if let Some(location) = workspace::last_opened_workspace_paths().await {
|
||||||
cx.update(|cx| workspace::open_paths(location.paths().as_ref(), app_state, None, cx))
|
cx.update(|cx| workspace::open_paths(location.paths().as_ref(), app_state, None, cx))
|
||||||
|
101
crates/zed/src/open_url.rs
Normal file
101
crates/zed/src/open_url.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
use cli::{ipc::IpcSender, CliRequest, CliResponse};
|
||||||
|
use futures::channel::mpsc;
|
||||||
|
use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::os::unix::prelude::OsStrExt;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
use std::{path::PathBuf, sync::atomic::AtomicBool};
|
||||||
|
use util::channel::URL_SCHEME_PREFIX;
|
||||||
|
use util::ResultExt;
|
||||||
|
|
||||||
|
use crate::{connect_to_cli, handle_cli_connection};
|
||||||
|
|
||||||
|
pub enum OpenRequest {
|
||||||
|
Paths {
|
||||||
|
paths: Vec<PathBuf>,
|
||||||
|
},
|
||||||
|
CliConnection {
|
||||||
|
connection: (mpsc::Receiver<CliRequest>, IpcSender<CliResponse>),
|
||||||
|
},
|
||||||
|
JoinChannel {
|
||||||
|
channel_id: u64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OpenListener {
|
||||||
|
tx: UnboundedSender<OpenRequest>,
|
||||||
|
pub triggered: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpenListener {
|
||||||
|
pub fn new() -> (Self, UnboundedReceiver<OpenRequest>) {
|
||||||
|
let (tx, rx) = mpsc::unbounded();
|
||||||
|
(
|
||||||
|
OpenListener {
|
||||||
|
tx,
|
||||||
|
triggered: AtomicBool::new(false),
|
||||||
|
},
|
||||||
|
rx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_urls(&self, urls: Vec<String>) {
|
||||||
|
self.triggered.store(true, Ordering::Release);
|
||||||
|
dbg!(&urls);
|
||||||
|
let request = if let Some(server_name) =
|
||||||
|
urls.first().and_then(|url| url.strip_prefix("zed-cli://"))
|
||||||
|
{
|
||||||
|
self.handle_cli_connection(server_name)
|
||||||
|
} else if let Some(request_path) = urls
|
||||||
|
.first()
|
||||||
|
.and_then(|url| url.strip_prefix(URL_SCHEME_PREFIX.as_str()))
|
||||||
|
{
|
||||||
|
self.handle_zed_url_scheme(request_path)
|
||||||
|
} else {
|
||||||
|
self.handle_file_urls(urls)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(request) = request {
|
||||||
|
self.tx
|
||||||
|
.unbounded_send(request)
|
||||||
|
.map_err(|_| anyhow!("no listener for open requests"))
|
||||||
|
.log_err();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_cli_connection(&self, server_name: &str) -> Option<OpenRequest> {
|
||||||
|
if let Some(connection) = connect_to_cli(server_name).log_err() {
|
||||||
|
return Some(OpenRequest::CliConnection { connection });
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_zed_url_scheme(&self, request_path: &str) -> Option<OpenRequest> {
|
||||||
|
let mut parts = request_path.split("/");
|
||||||
|
if parts.next() == Some("channel") {
|
||||||
|
if let Some(slug) = parts.next() {
|
||||||
|
if let Some(id_str) = slug.split("-").last() {
|
||||||
|
if let Ok(channel_id) = id_str.parse::<u64>() {
|
||||||
|
return Some(OpenRequest::JoinChannel { channel_id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_file_urls(&self, urls: Vec<String>) -> Option<OpenRequest> {
|
||||||
|
let paths: Vec<_> = urls
|
||||||
|
.iter()
|
||||||
|
.flat_map(|url| url.strip_prefix("file://"))
|
||||||
|
.map(|url| {
|
||||||
|
let decoded = urlencoding::decode_binary(url.as_bytes());
|
||||||
|
PathBuf::from(OsStr::from_bytes(decoded.as_ref()))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Some(OpenRequest::Paths { paths })
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user