mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
remote: Support line and column numbers for remote paths (#40410)
Closes #40297 Closes https://github.com/zed-industries/zed/issues/40367 Release Notes: - Improved line and column number handling for paths in remotes --------- Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
45a0d08535
commit
ca1f843a0b
9 changed files with 238 additions and 126 deletions
|
|
@ -98,7 +98,7 @@ impl AcpConnection {
|
|||
let stdout = child.stdout.take().context("Failed to take stdout")?;
|
||||
let stdin = child.stdin.take().context("Failed to take stdin")?;
|
||||
let stderr = child.stderr.take().context("Failed to take stderr")?;
|
||||
log::info!(
|
||||
log::debug!(
|
||||
"Spawning external agent server: {:?}, {:?}",
|
||||
command.path,
|
||||
command.args
|
||||
|
|
|
|||
15
crates/cli/README.md
Normal file
15
crates/cli/README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Cli
|
||||
|
||||
## Testing
|
||||
|
||||
You can test your changes to the `cli` crate by first building the main zed binary:
|
||||
|
||||
```
|
||||
cargo build -p zed
|
||||
```
|
||||
|
||||
And then building and running the `cli` crate with the following parameters:
|
||||
|
||||
```
|
||||
cargo run -p cli -- --zed ./target/debug/zed.exe
|
||||
```
|
||||
|
|
@ -155,6 +155,7 @@ fn parse_path_with_position(argument_str: &str) -> anyhow::Result<String> {
|
|||
}
|
||||
|
||||
fn parse_path_in_wsl(source: &str, wsl: &str) -> Result<String> {
|
||||
let mut source = PathWithPosition::parse_str(source);
|
||||
let mut command = util::command::new_std_command("wsl.exe");
|
||||
|
||||
let (user, distro_name) = if let Some((user, distro)) = wsl.split_once('@') {
|
||||
|
|
@ -173,19 +174,17 @@ fn parse_path_in_wsl(source: &str, wsl: &str) -> Result<String> {
|
|||
let output = command
|
||||
.arg("--distribution")
|
||||
.arg(distro_name)
|
||||
.arg("--exec")
|
||||
.arg("wslpath")
|
||||
.arg("-m")
|
||||
.arg(source)
|
||||
.arg(&source.path)
|
||||
.output()?;
|
||||
|
||||
let result = String::from_utf8_lossy(&output.stdout);
|
||||
let prefix = format!("//wsl.localhost/{}", distro_name);
|
||||
source.path = Path::new(result.trim().strip_prefix(&prefix).unwrap_or(&result)).to_owned();
|
||||
|
||||
Ok(result
|
||||
.trim()
|
||||
.strip_prefix(&prefix)
|
||||
.unwrap_or(&result)
|
||||
.to_string())
|
||||
Ok(source.to_string(|path| path.to_string_lossy().into_owned()))
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use std::{path::PathBuf, sync::Arc};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use askpass::EncryptedPassword;
|
||||
|
|
@ -12,11 +15,11 @@ use gpui::{
|
|||
TextStyleRefinement, WeakEntity,
|
||||
};
|
||||
|
||||
use language::CursorShape;
|
||||
use language::{CursorShape, Point};
|
||||
use markdown::{Markdown, MarkdownElement, MarkdownStyle};
|
||||
use release_channel::ReleaseChannel;
|
||||
use remote::{
|
||||
ConnectionIdentifier, RemoteClient, RemoteConnectionOptions, RemotePlatform,
|
||||
ConnectionIdentifier, RemoteClient, RemoteConnection, RemoteConnectionOptions, RemotePlatform,
|
||||
SshConnectionOptions,
|
||||
};
|
||||
pub use settings::SshConnection;
|
||||
|
|
@ -26,6 +29,7 @@ use ui::{
|
|||
ActiveTheme, Color, CommonAnimationExt, Context, Icon, IconName, IconSize, InteractiveElement,
|
||||
IntoElement, Label, LabelCommon, Styled, Window, prelude::*,
|
||||
};
|
||||
use util::paths::PathWithPosition;
|
||||
use workspace::{AppState, ModalView, Workspace};
|
||||
|
||||
pub struct SshSettings {
|
||||
|
|
@ -533,34 +537,6 @@ impl RemoteClientDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn connect_over_ssh(
|
||||
unique_identifier: ConnectionIdentifier,
|
||||
connection_options: SshConnectionOptions,
|
||||
ui: Entity<RemoteConnectionPrompt>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Option<Entity<RemoteClient>>>> {
|
||||
let window = window.window_handle();
|
||||
let known_password = connection_options
|
||||
.password
|
||||
.as_deref()
|
||||
.and_then(|pw| EncryptedPassword::try_from(pw).ok());
|
||||
let (tx, rx) = oneshot::channel();
|
||||
ui.update(cx, |ui, _cx| ui.set_cancellation_tx(tx));
|
||||
|
||||
remote::RemoteClient::ssh(
|
||||
unique_identifier,
|
||||
connection_options,
|
||||
rx,
|
||||
Arc::new(RemoteClientDelegate {
|
||||
window,
|
||||
ui: ui.downgrade(),
|
||||
known_password,
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn connect(
|
||||
unique_identifier: ConnectionIdentifier,
|
||||
connection_options: RemoteConnectionOptions,
|
||||
|
|
@ -579,17 +555,17 @@ pub fn connect(
|
|||
let (tx, rx) = oneshot::channel();
|
||||
ui.update(cx, |ui, _cx| ui.set_cancellation_tx(tx));
|
||||
|
||||
remote::RemoteClient::new(
|
||||
unique_identifier,
|
||||
connection_options,
|
||||
rx,
|
||||
Arc::new(RemoteClientDelegate {
|
||||
window,
|
||||
ui: ui.downgrade(),
|
||||
known_password,
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
let delegate = Arc::new(RemoteClientDelegate {
|
||||
window,
|
||||
ui: ui.downgrade(),
|
||||
known_password,
|
||||
});
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let connection = remote::connect(connection_options, delegate.clone(), cx).await?;
|
||||
cx.update(|cx| remote::RemoteClient::new(unique_identifier, connection, rx, delegate, cx))?
|
||||
.await
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn open_remote_project(
|
||||
|
|
@ -604,6 +580,7 @@ pub async fn open_remote_project(
|
|||
} else {
|
||||
let workspace_position = cx
|
||||
.update(|cx| {
|
||||
// todo: These paths are wrong they may have column and line information
|
||||
workspace::remote_workspace_position_from_db(connection_options.clone(), &paths, cx)
|
||||
})?
|
||||
.await
|
||||
|
|
@ -671,11 +648,16 @@ pub async fn open_remote_project(
|
|||
|
||||
let Some(delegate) = delegate else { break };
|
||||
|
||||
let did_open_project = cx
|
||||
let remote_connection =
|
||||
remote::connect(connection_options.clone(), delegate.clone(), cx).await?;
|
||||
let (paths, paths_with_positions) =
|
||||
determine_paths_with_positions(&remote_connection, paths.clone()).await;
|
||||
|
||||
let opened_items = cx
|
||||
.update(|cx| {
|
||||
workspace::open_remote_project_with_new_connection(
|
||||
window,
|
||||
connection_options.clone(),
|
||||
remote_connection,
|
||||
cancel_rx,
|
||||
delegate.clone(),
|
||||
app_state.clone(),
|
||||
|
|
@ -693,25 +675,51 @@ pub async fn open_remote_project(
|
|||
})
|
||||
.ok();
|
||||
|
||||
if let Err(e) = did_open_project {
|
||||
log::error!("Failed to open project: {e:?}");
|
||||
let response = window
|
||||
.update(cx, |_, window, cx| {
|
||||
window.prompt(
|
||||
PromptLevel::Critical,
|
||||
match connection_options {
|
||||
RemoteConnectionOptions::Ssh(_) => "Failed to connect over SSH",
|
||||
RemoteConnectionOptions::Wsl(_) => "Failed to connect to WSL",
|
||||
},
|
||||
Some(&e.to_string()),
|
||||
&["Retry", "Ok"],
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await;
|
||||
|
||||
if response == Ok(0) {
|
||||
continue;
|
||||
match opened_items {
|
||||
Err(e) => {
|
||||
log::error!("Failed to open project: {e:?}");
|
||||
let response = window
|
||||
.update(cx, |_, window, cx| {
|
||||
window.prompt(
|
||||
PromptLevel::Critical,
|
||||
match connection_options {
|
||||
RemoteConnectionOptions::Ssh(_) => "Failed to connect over SSH",
|
||||
RemoteConnectionOptions::Wsl(_) => "Failed to connect to WSL",
|
||||
},
|
||||
Some(&e.to_string()),
|
||||
&["Retry", "Ok"],
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await;
|
||||
if response == Ok(0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Ok(items) => {
|
||||
for (item, path) in items.into_iter().zip(paths_with_positions) {
|
||||
let Some(item) = item else {
|
||||
continue;
|
||||
};
|
||||
let Some(row) = path.row else {
|
||||
continue;
|
||||
};
|
||||
if let Some(active_editor) = item.downcast::<Editor>() {
|
||||
window
|
||||
.update(cx, |_, window, cx| {
|
||||
active_editor.update(cx, |editor, cx| {
|
||||
let row = row.saturating_sub(1);
|
||||
let col = path.column.unwrap_or(0).saturating_sub(1);
|
||||
editor.go_to_singleton_buffer_point(
|
||||
Point::new(row, col),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -730,3 +738,44 @@ pub async fn open_remote_project(
|
|||
// Already showed the error to the user
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn determine_paths_with_positions(
|
||||
remote_connection: &Arc<dyn RemoteConnection>,
|
||||
mut paths: Vec<PathBuf>,
|
||||
) -> (Vec<PathBuf>, Vec<PathWithPosition>) {
|
||||
let mut paths_with_positions = Vec::<PathWithPosition>::new();
|
||||
for path in &mut paths {
|
||||
if let Some(path_str) = path.to_str() {
|
||||
let path_with_position = PathWithPosition::parse_str(&path_str);
|
||||
if path_with_position.row.is_some() {
|
||||
if !path_exists(&remote_connection, &path).await {
|
||||
*path = path_with_position.path.clone();
|
||||
paths_with_positions.push(path_with_position);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
paths_with_positions.push(PathWithPosition::from_path(path.clone()))
|
||||
}
|
||||
(paths, paths_with_positions)
|
||||
}
|
||||
|
||||
async fn path_exists(connection: &Arc<dyn RemoteConnection>, path: &Path) -> bool {
|
||||
let Ok(command) = connection.build_command(
|
||||
Some("test".to_string()),
|
||||
&["-e".to_owned(), path.to_string_lossy().to_string()],
|
||||
&Default::default(),
|
||||
None,
|
||||
None,
|
||||
) else {
|
||||
return false;
|
||||
};
|
||||
let Ok(mut child) = util::command::new_smol_command(command.program)
|
||||
.args(command.args)
|
||||
.envs(command.env)
|
||||
.spawn()
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
child.status().await.is_ok_and(|status| status.success())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{
|
||||
remote_connections::{
|
||||
Connection, RemoteConnectionModal, RemoteConnectionPrompt, SshConnection,
|
||||
SshConnectionHeader, SshSettings, connect, connect_over_ssh, open_remote_project,
|
||||
SshConnectionHeader, SshSettings, connect, determine_paths_with_positions,
|
||||
open_remote_project,
|
||||
},
|
||||
ssh_config::parse_ssh_config_hosts,
|
||||
};
|
||||
|
|
@ -13,6 +14,7 @@ use gpui::{
|
|||
FocusHandle, Focusable, PromptLevel, ScrollHandle, Subscription, Task, WeakEntity, Window,
|
||||
canvas,
|
||||
};
|
||||
use language::Point;
|
||||
use log::info;
|
||||
use paths::{global_ssh_config_file, user_ssh_config_file};
|
||||
use picker::Picker;
|
||||
|
|
@ -233,6 +235,15 @@ impl ProjectPicker {
|
|||
.read_with(cx, |workspace, _| workspace.app_state().clone())
|
||||
.ok()?;
|
||||
|
||||
let remote_connection = project
|
||||
.read_with(cx, |project, cx| {
|
||||
project.remote_client()?.read(cx).connection()
|
||||
})
|
||||
.ok()??;
|
||||
|
||||
let (paths, paths_with_positions) =
|
||||
determine_paths_with_positions(&remote_connection, paths).await;
|
||||
|
||||
cx.update(|_, cx| {
|
||||
let fs = app_state.fs.clone();
|
||||
update_settings_file(fs, cx, {
|
||||
|
|
@ -278,12 +289,38 @@ impl ProjectPicker {
|
|||
})
|
||||
.log_err()?;
|
||||
|
||||
open_remote_project_with_existing_connection(
|
||||
let items = open_remote_project_with_existing_connection(
|
||||
connection, project, paths, app_state, window, cx,
|
||||
)
|
||||
.await
|
||||
.log_err();
|
||||
|
||||
if let Some(items) = items {
|
||||
for (item, path) in items.into_iter().zip(paths_with_positions) {
|
||||
let Some(item) = item else {
|
||||
continue;
|
||||
};
|
||||
let Some(row) = path.row else {
|
||||
continue;
|
||||
};
|
||||
if let Some(active_editor) = item.downcast::<Editor>() {
|
||||
window
|
||||
.update(cx, |_, window, cx| {
|
||||
active_editor.update(cx, |editor, cx| {
|
||||
let row = row.saturating_sub(1);
|
||||
let col = path.column.unwrap_or(0).saturating_sub(1);
|
||||
editor.go_to_singleton_buffer_point(
|
||||
Point::new(row, col),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.update(cx, |_, cx| {
|
||||
cx.emit(DismissEvent);
|
||||
})
|
||||
|
|
@ -671,9 +708,9 @@ impl RemoteServerProjects {
|
|||
)
|
||||
});
|
||||
|
||||
let connection = connect_over_ssh(
|
||||
let connection = connect(
|
||||
ConnectionIdentifier::setup(),
|
||||
connection_options.clone(),
|
||||
RemoteConnectionOptions::Ssh(connection_options.clone()),
|
||||
ssh_prompt.clone(),
|
||||
window,
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ mod transport;
|
|||
|
||||
pub use remote_client::{
|
||||
ConnectionIdentifier, ConnectionState, RemoteClient, RemoteClientDelegate, RemoteClientEvent,
|
||||
RemoteConnectionOptions, RemotePlatform,
|
||||
RemoteConnection, RemoteConnectionOptions, RemotePlatform, connect,
|
||||
};
|
||||
pub use transport::ssh::{SshConnectionOptions, SshPortForwardOption};
|
||||
pub use transport::wsl::WslConnectionOptions;
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ const MAX_RECONNECT_ATTEMPTS: usize = 3;
|
|||
enum State {
|
||||
Connecting,
|
||||
Connected {
|
||||
ssh_connection: Arc<dyn RemoteConnection>,
|
||||
remote_connection: Arc<dyn RemoteConnection>,
|
||||
delegate: Arc<dyn RemoteClientDelegate>,
|
||||
|
||||
multiplex_task: Task<Result<()>>,
|
||||
|
|
@ -137,7 +137,10 @@ impl fmt::Display for State {
|
|||
impl State {
|
||||
fn remote_connection(&self) -> Option<Arc<dyn RemoteConnection>> {
|
||||
match self {
|
||||
Self::Connected { ssh_connection, .. } => Some(ssh_connection.clone()),
|
||||
Self::Connected {
|
||||
remote_connection: ssh_connection,
|
||||
..
|
||||
} => Some(ssh_connection.clone()),
|
||||
Self::HeartbeatMissed { ssh_connection, .. } => Some(ssh_connection.clone()),
|
||||
Self::ReconnectFailed { ssh_connection, .. } => Some(ssh_connection.clone()),
|
||||
_ => None,
|
||||
|
|
@ -181,7 +184,7 @@ impl State {
|
|||
heartbeat_task,
|
||||
..
|
||||
} => Self::Connected {
|
||||
ssh_connection,
|
||||
remote_connection: ssh_connection,
|
||||
delegate,
|
||||
multiplex_task,
|
||||
heartbeat_task,
|
||||
|
|
@ -193,7 +196,7 @@ impl State {
|
|||
fn heartbeat_missed(self) -> Self {
|
||||
match self {
|
||||
Self::Connected {
|
||||
ssh_connection,
|
||||
remote_connection: ssh_connection,
|
||||
delegate,
|
||||
multiplex_task,
|
||||
heartbeat_task,
|
||||
|
|
@ -260,8 +263,8 @@ pub enum RemoteClientEvent {
|
|||
|
||||
impl EventEmitter<RemoteClientEvent> for RemoteClient {}
|
||||
|
||||
// Identifies the socket on the remote server so that reconnects
|
||||
// can re-join the same project.
|
||||
/// Identifies the socket on the remote server so that reconnects
|
||||
/// can re-join the same project.
|
||||
pub enum ConnectionIdentifier {
|
||||
Setup(u64),
|
||||
Workspace(i64),
|
||||
|
|
@ -294,26 +297,24 @@ impl ConnectionIdentifier {
|
|||
}
|
||||
}
|
||||
|
||||
impl RemoteClient {
|
||||
pub fn ssh(
|
||||
unique_identifier: ConnectionIdentifier,
|
||||
connection_options: SshConnectionOptions,
|
||||
cancellation: oneshot::Receiver<()>,
|
||||
delegate: Arc<dyn RemoteClientDelegate>,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Option<Entity<Self>>>> {
|
||||
Self::new(
|
||||
unique_identifier,
|
||||
RemoteConnectionOptions::Ssh(connection_options),
|
||||
cancellation,
|
||||
delegate,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
pub async fn connect(
|
||||
connection_options: RemoteConnectionOptions,
|
||||
delegate: Arc<dyn RemoteClientDelegate>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<Arc<dyn RemoteConnection>> {
|
||||
cx.update(|cx| {
|
||||
cx.update_default_global(|pool: &mut ConnectionPool, cx| {
|
||||
pool.connect(connection_options.clone(), delegate.clone(), cx)
|
||||
})
|
||||
})?
|
||||
.await
|
||||
.map_err(|e| e.cloned())
|
||||
}
|
||||
|
||||
impl RemoteClient {
|
||||
pub fn new(
|
||||
unique_identifier: ConnectionIdentifier,
|
||||
connection_options: RemoteConnectionOptions,
|
||||
remote_connection: Arc<dyn RemoteConnection>,
|
||||
cancellation: oneshot::Receiver<()>,
|
||||
delegate: Arc<dyn RemoteClientDelegate>,
|
||||
cx: &mut App,
|
||||
|
|
@ -328,25 +329,16 @@ impl RemoteClient {
|
|||
let client =
|
||||
cx.update(|cx| ChannelClient::new(incoming_rx, outgoing_tx, cx, "client"))?;
|
||||
|
||||
let ssh_connection = cx
|
||||
.update(|cx| {
|
||||
cx.update_default_global(|pool: &mut ConnectionPool, cx| {
|
||||
pool.connect(connection_options.clone(), delegate.clone(), cx)
|
||||
})
|
||||
})?
|
||||
.await
|
||||
.map_err(|e| e.cloned())?;
|
||||
|
||||
let path_style = ssh_connection.path_style();
|
||||
let path_style = remote_connection.path_style();
|
||||
let this = cx.new(|_| Self {
|
||||
client: client.clone(),
|
||||
unique_identifier: unique_identifier.clone(),
|
||||
connection_options,
|
||||
connection_options: remote_connection.connection_options(),
|
||||
path_style,
|
||||
state: Some(State::Connecting),
|
||||
})?;
|
||||
|
||||
let io_task = ssh_connection.start_proxy(
|
||||
let io_task = remote_connection.start_proxy(
|
||||
unique_identifier,
|
||||
false,
|
||||
incoming_tx,
|
||||
|
|
@ -402,7 +394,7 @@ impl RemoteClient {
|
|||
|
||||
this.update(cx, |this, _| {
|
||||
this.state = Some(State::Connected {
|
||||
ssh_connection,
|
||||
remote_connection,
|
||||
delegate,
|
||||
multiplex_task,
|
||||
heartbeat_task,
|
||||
|
|
@ -441,7 +433,7 @@ impl RemoteClient {
|
|||
let State::Connected {
|
||||
multiplex_task,
|
||||
heartbeat_task,
|
||||
ssh_connection,
|
||||
remote_connection: ssh_connection,
|
||||
delegate,
|
||||
} = state
|
||||
else {
|
||||
|
|
@ -488,7 +480,7 @@ impl RemoteClient {
|
|||
let state = self.state.take().unwrap();
|
||||
let (attempts, remote_connection, delegate) = match state {
|
||||
State::Connected {
|
||||
ssh_connection,
|
||||
remote_connection: ssh_connection,
|
||||
delegate,
|
||||
multiplex_task,
|
||||
heartbeat_task,
|
||||
|
|
@ -593,7 +585,7 @@ impl RemoteClient {
|
|||
};
|
||||
|
||||
State::Connected {
|
||||
ssh_connection,
|
||||
remote_connection: ssh_connection,
|
||||
delegate,
|
||||
multiplex_task,
|
||||
heartbeat_task: Self::heartbeat(this.clone(), connection_activity_rx, cx),
|
||||
|
|
@ -866,6 +858,17 @@ impl RemoteClient {
|
|||
self.connection_options.clone()
|
||||
}
|
||||
|
||||
pub fn connection(&self) -> Option<Arc<dyn RemoteConnection>> {
|
||||
if let State::Connected {
|
||||
remote_connection, ..
|
||||
} = self.state.as_ref()?
|
||||
{
|
||||
Some(remote_connection.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connection_state(&self) -> ConnectionState {
|
||||
self.state
|
||||
.as_ref()
|
||||
|
|
@ -947,11 +950,15 @@ impl RemoteClient {
|
|||
client_cx: &mut gpui::TestAppContext,
|
||||
) -> Entity<Self> {
|
||||
let (_tx, rx) = oneshot::channel();
|
||||
let mut cx = client_cx.to_async();
|
||||
let connection = connect(opts, Arc::new(fake::Delegate), &mut cx)
|
||||
.await
|
||||
.unwrap();
|
||||
client_cx
|
||||
.update(|cx| {
|
||||
Self::new(
|
||||
ConnectionIdentifier::setup(),
|
||||
opts,
|
||||
connection,
|
||||
rx,
|
||||
Arc::new(fake::Delegate),
|
||||
cx,
|
||||
|
|
@ -1084,7 +1091,7 @@ impl From<WslConnectionOptions> for RemoteConnectionOptions {
|
|||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub(crate) trait RemoteConnection: Send + Sync {
|
||||
pub trait RemoteConnection: Send + Sync {
|
||||
fn start_proxy(
|
||||
&self,
|
||||
unique_identifier: String,
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ async fn build_remote_server_from_source(
|
|||
log::info!("building remote server binary from source");
|
||||
run_cmd(
|
||||
Command::new("cargo")
|
||||
.current_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/../.."))
|
||||
.args([
|
||||
"build",
|
||||
"--package",
|
||||
|
|
|
|||
|
|
@ -76,7 +76,10 @@ use project::{
|
|||
debugger::{breakpoint_store::BreakpointStoreEvent, session::ThreadStatus},
|
||||
toolchain_store::ToolchainStoreEvent,
|
||||
};
|
||||
use remote::{RemoteClientDelegate, RemoteConnectionOptions, remote_client::ConnectionIdentifier};
|
||||
use remote::{
|
||||
RemoteClientDelegate, RemoteConnection, RemoteConnectionOptions,
|
||||
remote_client::ConnectionIdentifier,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use session::AppSession;
|
||||
|
|
@ -7441,22 +7444,23 @@ pub fn create_and_open_local_file(
|
|||
|
||||
pub fn open_remote_project_with_new_connection(
|
||||
window: WindowHandle<Workspace>,
|
||||
connection_options: RemoteConnectionOptions,
|
||||
remote_connection: Arc<dyn RemoteConnection>,
|
||||
cancel_rx: oneshot::Receiver<()>,
|
||||
delegate: Arc<dyn RemoteClientDelegate>,
|
||||
app_state: Arc<AppState>,
|
||||
paths: Vec<PathBuf>,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<()>> {
|
||||
) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> {
|
||||
cx.spawn(async move |cx| {
|
||||
let (workspace_id, serialized_workspace) =
|
||||
serialize_remote_project(connection_options.clone(), paths.clone(), cx).await?;
|
||||
serialize_remote_project(remote_connection.connection_options(), paths.clone(), cx)
|
||||
.await?;
|
||||
|
||||
let session = match cx
|
||||
.update(|cx| {
|
||||
remote::RemoteClient::new(
|
||||
ConnectionIdentifier::Workspace(workspace_id.0),
|
||||
connection_options,
|
||||
remote_connection,
|
||||
cancel_rx,
|
||||
delegate,
|
||||
cx,
|
||||
|
|
@ -7465,7 +7469,7 @@ pub fn open_remote_project_with_new_connection(
|
|||
.await?
|
||||
{
|
||||
Some(result) => result,
|
||||
None => return Ok(()),
|
||||
None => return Ok(Vec::new()),
|
||||
};
|
||||
|
||||
let project = cx.update(|cx| {
|
||||
|
|
@ -7500,7 +7504,7 @@ pub fn open_remote_project_with_existing_connection(
|
|||
app_state: Arc<AppState>,
|
||||
window: WindowHandle<Workspace>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Task<Result<()>> {
|
||||
) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> {
|
||||
cx.spawn(async move |cx| {
|
||||
let (workspace_id, serialized_workspace) =
|
||||
serialize_remote_project(connection_options.clone(), paths.clone(), cx).await?;
|
||||
|
|
@ -7526,7 +7530,7 @@ async fn open_remote_project_inner(
|
|||
app_state: Arc<AppState>,
|
||||
window: WindowHandle<Workspace>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<()> {
|
||||
) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
|
||||
let toolchains = DB.toolchains(workspace_id).await?;
|
||||
for (toolchain, worktree_id, path) in toolchains {
|
||||
project
|
||||
|
|
@ -7583,7 +7587,7 @@ async fn open_remote_project_inner(
|
|||
});
|
||||
})?;
|
||||
|
||||
window
|
||||
let items = window
|
||||
.update(cx, |_, window, cx| {
|
||||
window.activate_window();
|
||||
open_items(serialized_workspace, project_paths_to_open, window, cx)
|
||||
|
|
@ -7602,7 +7606,7 @@ async fn open_remote_project_inner(
|
|||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
Ok(items.into_iter().map(|item| item?.ok()).collect())
|
||||
}
|
||||
|
||||
fn serialize_remote_project(
|
||||
|
|
|
|||
Loading…
Reference in a new issue