SFTP 本地目录列表在 Windows 上列出各个驱动器

Windows 上每个盘是一个独立的根,目录列表原来只有当前路径的各级和主目录、桌面、文稿、下载,
离不开起始的盘(只能在「打开目录/书签」里手动输入 D:\)。现在「位置」里按 WinSCP 的样子
列出所有盘符:「C: 本地磁盘」「E: 可移动磁盘」「Z: 网络驱动器」「F: CD 驱动器」。

盘符用 GetLogicalDrives 和 GetDriveTypeW 取,不读卷标。位置改在后台随每次读本地目录
一起重新取,所以新插上的 U 盘刷新一下就出现,也不在 UI 线程上碰网络驱动器。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
XuzandClaude Opus 5.5 committed 2026-10-10 13:46:54 +08:00
1 parent 5be3f56b0c
commit e1600ce05c
10 files changed
+184 -24

No files matched your search

+44
View File
@@ -1271,6 +1271,50 @@ async fn sftp_tab_reconnects_from_its_tab_bar_and_reports_at_the_bottom_left(
cx.update(|cx| assert_eq!(workspace.read(cx).explorers_of(HostId(DB_01), cx).len(), 2));
}
/// The 目录列表 select's places, Windows drives among them, are read again
/// with each local listing: a drive plugged in shows up on the next refresh.
#[gpui_kit::test]
async fn local_places_are_read_again_with_each_listing(cx: &mut TestAppContext) {
use shellrs::app::{ExplorerAction, ExplorerCommand};
use shellrs::sftp::{DriveKind, Place};
let local = FakeLocalDirectory::default();
let system = (Place::Drive('C', DriveKind::Local), "/c".to_string());
local
.places
.lock()
.unwrap()
.push((system.0, system.1.clone().into()));
let (handle, workspace) =
open_workspace_with_services(cx, Arc::new(FakeSftpProvider::default()), local.clone());
open_test_explorer(cx, handle).await;
let places = |cx: &mut TestAppContext| {
cx.update(|cx| {
let explorer = workspace.read(cx).explorer(ExplorerId(SFTP_TAB)).unwrap();
explorer.read(cx).local().read(cx).places().to_vec()
})
};
assert_eq!(places(cx), std::slice::from_ref(&system));
let stick = (Place::Drive('E', DriveKind::Removable), "/e".to_string());
local
.places
.lock()
.unwrap()
.push((stick.0, stick.1.clone().into()));
cx.update_window(handle.into(), |_, window, cx| {
window.dispatch_action(
Box::new(ExplorerAction::new(
ExplorerId(SFTP_TAB),
ExplorerCommand::Refresh { remote: false },
)),
cx,
);
})
.unwrap();
cx.run_until_parked();
assert_eq!(places(cx), [system, stick]);
}
#[gpui_kit::test]
async fn sftp_file_commands_confirm_validate_and_send_one_operation(cx: &mut TestAppContext) {
use shellrs::app::{ExplorerAction, ExplorerCommand};
+5
View File
@@ -271,6 +271,8 @@ pub struct FakeLocalDirectory {
pub calls: Arc<Mutex<Vec<String>>>,
/// The files the editor reads and writes, in memory.
pub files: Arc<Mutex<std::collections::BTreeMap<std::path::PathBuf, Vec<u8>>>>,
/// The places it offers, such as a drive plugged in.
pub places: Arc<Mutex<Vec<(shellrs::sftp::Place, std::path::PathBuf)>>>,
}
impl FakeLocalDirectory {
@@ -287,6 +289,9 @@ impl LocalDirectoryProvider for FakeLocalDirectory {
fn list(&self, path: &std::path::Path) -> anyhow::Result<DirectoryListing> {
Ok(fake_listing(path.to_str().unwrap()))
}
fn places(&self) -> Vec<(shellrs::sftp::Place, std::path::PathBuf)> {
self.places.lock().unwrap().clone()
}
fn trash(&self, paths: &[std::path::PathBuf]) -> anyhow::Result<()> {
self.record(format!("trash {paths:?}"))
}