@@ -1,7 +1,7 @@
use futures::channel::oneshot;
use fuzzy::{StringMatch, StringMatchCandidate};
use picker::{Picker, PickerDelegate};
-use project::DirectoryLister;
+use project::{DirectoryItem, DirectoryLister};
use std::{
path::{MAIN_SEPARATOR_STR, Path, PathBuf},
sync::{
@@ -137,6 +137,7 @@ impl PickerDelegate for OpenPathDelegate {
} else {
(query, String::new())
};
+
if dir == "" {
#[cfg(not(target_os = "windows"))]
{
@@ -171,6 +172,13 @@ impl PickerDelegate for OpenPathDelegate {
this.update(cx, |this, _| {
this.delegate.directory_state = Some(match paths {
Ok(mut paths) => {
+ if dir == "/" {
+ paths.push(DirectoryItem {
+ is_dir: true,
+ path: Default::default(),
+ });
+ }
+
paths.sort_by(|a, b| compare_paths((&a.path, true), (&b.path, true)));
let match_candidates = paths
.iter()
@@ -309,12 +317,16 @@ impl PickerDelegate for OpenPathDelegate {
let Some(candidate) = directory_state.match_candidates.get(*m) else {
return;
};
- let result = Path::new(
- self.lister
- .resolve_tilde(&directory_state.path, cx)
- .as_ref(),
- )
- .join(&candidate.path.string);
+ let result = if directory_state.path == "/" && candidate.path.string.is_empty() {
+ PathBuf::from("/")
+ } else {
+ Path::new(
+ self.lister
+ .resolve_tilde(&directory_state.path, cx)
+ .as_ref(),
+ )
+ .join(&candidate.path.string)
+ };
if let Some(tx) = self.tx.take() {
tx.send(Some(vec![result])).ok();
}
@@ -355,7 +367,11 @@ impl PickerDelegate for OpenPathDelegate {
.inset(true)
.toggle_state(selected)
.child(HighlightedLabel::new(
- candidate.path.string.clone(),
+ if directory_state.path == "/" {
+ format!("/{}", candidate.path.string)
+ } else {
+ candidate.path.string.clone()
+ },
highlight_positions,
)),
)
@@ -124,20 +124,20 @@ impl ProjectPicker {
ix: usize,
connection: SshConnectionOptions,
project: Entity<Project>,
+ home_dir: PathBuf,
workspace: WeakEntity<Workspace>,
window: &mut Window,
cx: &mut Context<RemoteServerProjects>,
) -> Entity<Self> {
let (tx, rx) = oneshot::channel();
let lister = project::DirectoryLister::Project(project.clone());
- let query = lister.default_query(cx);
let delegate = file_finder::OpenPathDelegate::new(tx, lister);
let picker = cx.new(|cx| {
let picker = Picker::uniform_list(delegate, window, cx)
.width(rems(34.))
.modal(false);
- picker.set_query(query, window, cx);
+ picker.set_query(home_dir.to_string_lossy().to_string(), window, cx);
picker
});
let connection_string = connection.connection_string().into();
@@ -345,6 +345,7 @@ impl RemoteServerProjects {
ix: usize,
connection_options: remote::SshConnectionOptions,
project: Entity<Project>,
+ home_dir: PathBuf,
window: &mut Window,
cx: &mut Context<Self>,
workspace: WeakEntity<Workspace>,
@@ -354,6 +355,7 @@ impl RemoteServerProjects {
ix,
connection_options,
project,
+ home_dir,
workspace,
window,
cx,
@@ -467,6 +469,7 @@ impl RemoteServerProjects {
let connection_options = ssh_connection.into();
workspace.update(cx, |_, cx| {
cx.defer_in(window, move |workspace, window, cx| {
+ let app_state = workspace.app_state().clone();
workspace.toggle_modal(window, cx, |window, cx| {
SshConnectionModal::new(&connection_options, Vec::new(), window, cx)
});
@@ -489,44 +492,48 @@ impl RemoteServerProjects {
cx.spawn_in(window, async move |workspace, cx| {
let session = connect.await;
- workspace
- .update(cx, |workspace, cx| {
- if let Some(prompt) = workspace.active_modal::<SshConnectionModal>(cx) {
- prompt.update(cx, |prompt, cx| prompt.finished(cx))
- }
- })
- .ok();
+ workspace.update(cx, |workspace, cx| {
+ if let Some(prompt) = workspace.active_modal::<SshConnectionModal>(cx) {
+ prompt.update(cx, |prompt, cx| prompt.finished(cx))
+ }
+ })?;
let Some(Some(session)) = session else {
- workspace
- .update_in(cx, |workspace, window, cx| {
- let weak = cx.entity().downgrade();
- workspace.toggle_modal(window, cx, |window, cx| {
- RemoteServerProjects::new(window, cx, weak)
- });
- })
- .log_err();
- return;
+ return workspace.update_in(cx, |workspace, window, cx| {
+ let weak = cx.entity().downgrade();
+ workspace.toggle_modal(window, cx, |window, cx| {
+ RemoteServerProjects::new(window, cx, weak)
+ });
+ });
};
+ let project = cx.update(|_, cx| {
+ project::Project::ssh(
+ session,
+ app_state.client.clone(),
+ app_state.node_runtime.clone(),
+ app_state.user_store.clone(),
+ app_state.languages.clone(),
+ app_state.fs.clone(),
+ cx,
+ )
+ })?;
+
+ let home_dir = project
+ .read_with(cx, |project, cx| project.resolve_abs_path("~", cx))?
+ .await
+ .and_then(|path| path.into_abs_path())
+ .unwrap_or(PathBuf::from("/"));
+
workspace
.update_in(cx, |workspace, window, cx| {
- let app_state = workspace.app_state().clone();
let weak = cx.entity().downgrade();
- let project = project::Project::ssh(
- session,
- app_state.client.clone(),
- app_state.node_runtime.clone(),
- app_state.user_store.clone(),
- app_state.languages.clone(),
- app_state.fs.clone(),
- cx,
- );
workspace.toggle_modal(window, cx, |window, cx| {
RemoteServerProjects::project_picker(
ix,
connection_options,
project,
+ home_dir,
window,
cx,
weak,
@@ -534,8 +541,9 @@ impl RemoteServerProjects {
});
})
.ok();
+ Ok(())
})
- .detach()
+ .detach();
})
})
}
@@ -530,8 +530,8 @@ pub async fn derive_paths_with_position(
#[cfg(test)]
mod tests {
- use std::sync::Arc;
-
+ use super::*;
+ use crate::zed::{open_listener::open_local_workspace, tests::init_test};
use cli::{
CliResponse,
ipc::{self},
@@ -539,10 +539,33 @@ mod tests {
use editor::Editor;
use gpui::TestAppContext;
use serde_json::json;
+ use std::sync::Arc;
use util::path;
use workspace::{AppState, Workspace};
- use crate::zed::{open_listener::open_local_workspace, tests::init_test};
+ #[gpui::test]
+ fn test_parse_ssh_url(cx: &mut TestAppContext) {
+ let _app_state = init_test(cx);
+ cx.update(|cx| {
+ SshSettings::register(cx);
+ });
+ let request =
+ cx.update(|cx| OpenRequest::parse(vec!["ssh://me@localhost:/".into()], cx).unwrap());
+ assert_eq!(
+ request.ssh_connection.unwrap(),
+ SshConnectionOptions {
+ host: "localhost".into(),
+ username: Some("me".into()),
+ port: None,
+ password: None,
+ args: None,
+ port_forwards: None,
+ nickname: None,
+ upload_binary_over_ssh: false,
+ }
+ );
+ assert_eq!(request.open_paths, vec!["/"]);
+ }
#[gpui::test]
async fn test_open_workspace_with_directory(cx: &mut TestAppContext) {