Merge remote-tracking branch 'origin/main' into review/266-integration-20260924
This commit is contained in:
commit
4599f18def
7 files changed
+104
-23
No files matched your search
@@ -64,6 +64,21 @@ impl SshHostLists {
|
||||
)
|
||||
}
|
||||
|
||||
/// 与 [`Self::merged`] 同一顺序权威,同时带出用户在 SSH 设置里起的
|
||||
/// 主机名称(地址 → 别名;没起名的是空串,展示端回落地址本身)。
|
||||
/// profiles 在 [`Self::load`] 时已经读盘,这里不重复读 JSON;launcher /
|
||||
/// Quick Jump / 命令面板三处 SSH 行共用,避免各自再解析一次。
|
||||
pub fn merged_with_labels(&self) -> Vec<(String, String)> {
|
||||
let labels = self.profiles.labels();
|
||||
self.merged()
|
||||
.into_iter()
|
||||
.map(|host| {
|
||||
let label = labels.get(&host).cloned().unwrap_or_default();
|
||||
(host, label)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 隐藏区(设置页"已隐藏"折叠列表的数据源)。
|
||||
pub fn hidden_hosts(&self) -> Vec<String> {
|
||||
self.hidden.iter().filter(|host| self.configured.contains(host)).cloned().collect()
|
||||
|
||||
@@ -2228,7 +2228,7 @@ impl NebulaWorkspace {
|
||||
crate::terminal_profiles::TerminalProfiles::load()
|
||||
.map(|store| store.as_config_profiles())
|
||||
.unwrap_or_default(),
|
||||
crate::gpui_shell::ssh_hosts::SshHostLists::load().merged(),
|
||||
crate::gpui_shell::ssh_hosts::SshHostLists::load().merged_with_labels(),
|
||||
&default_shell_id,
|
||||
language,
|
||||
window.scale_factor().max(0.5),
|
||||
|
||||
@@ -37,7 +37,7 @@ fn open(cx: &mut TestAppContext) -> (Entity<NebulaWorkspace>, VisualTestContext)
|
||||
workspace.palette_override = Some(shell_palette_rows(
|
||||
vec![shell("cmd"), shell("pwsh")],
|
||||
vec![],
|
||||
["test-host".into()],
|
||||
[("test-host".into(), String::new())],
|
||||
"cmd",
|
||||
workspace_ui_language(),
|
||||
1.0,
|
||||
|
||||
@@ -100,26 +100,31 @@ impl NebulaWorkspace {
|
||||
// 次序由共享 merge 权威裁定。
|
||||
let ssh_icons = ssh_host_icon_ids(&crate::display::nebula_data_dir());
|
||||
rows.extend(
|
||||
crate::gpui_shell::ssh_hosts::SshHostLists::load().merged().into_iter().map(
|
||||
|host| {
|
||||
crate::gpui_shell::ssh_hosts::SshHostLists::load()
|
||||
.merged_with_labels()
|
||||
.into_iter()
|
||||
.map(|(host, label)| {
|
||||
let glyph = crate::display::ui::os_icons::resolve(
|
||||
ssh_icons.get(&host).map(String::as_str),
|
||||
)
|
||||
.glyph;
|
||||
let named = (!label.is_empty()).then_some(label.as_str());
|
||||
let (label, hint) = shell_picker::ssh_host_display(named, &host);
|
||||
let search =
|
||||
format!("{label} {host} ssh host remote lianjie 连接").to_lowercase();
|
||||
WorkspacePaletteRow {
|
||||
group_order: usize::MAX,
|
||||
group: language.pick("SSH 主机", "SSH HOSTS").to_owned(),
|
||||
label: host.clone(),
|
||||
hint: "SSH".to_owned(),
|
||||
label,
|
||||
hint,
|
||||
hint_style: WorkspacePaletteHintStyle::Metadata,
|
||||
search: format!("{host} ssh host remote lianjie 连接").to_lowercase(),
|
||||
search,
|
||||
action: WorkspacePaletteAction::LaunchSshHost(host),
|
||||
icon: None,
|
||||
icon_glyph: Some(glyph),
|
||||
icon_path: None,
|
||||
}
|
||||
},
|
||||
),
|
||||
}),
|
||||
);
|
||||
rows
|
||||
});
|
||||
|
||||
@@ -143,18 +143,21 @@ fn ssh_rows(language: crate::display::UiLanguage) -> Vec<WorkspacePaletteRow> {
|
||||
let group = language.pick("SSH 主机", "SSH hosts");
|
||||
let icons = ssh_host_icon_ids(&crate::display::nebula_data_dir());
|
||||
crate::gpui_shell::ssh_hosts::SshHostLists::load()
|
||||
.merged()
|
||||
.merged_with_labels()
|
||||
.into_iter()
|
||||
.map(|host| {
|
||||
.map(|(host, label)| {
|
||||
let glyph =
|
||||
crate::display::ui::os_icons::resolve(icons.get(&host).map(String::as_str)).glyph;
|
||||
let named = (!label.is_empty()).then_some(label.as_str());
|
||||
let (label, hint) = shell_picker::ssh_host_display(named, &host);
|
||||
let search = format!("{label} {host} ssh host remote 远程 连接").to_lowercase();
|
||||
WorkspacePaletteRow {
|
||||
group_order: 3,
|
||||
group: group.to_owned(),
|
||||
label: host.clone(),
|
||||
hint: "SSH".to_owned(),
|
||||
label,
|
||||
hint,
|
||||
hint_style: super::WorkspacePaletteHintStyle::Metadata,
|
||||
search: format!("{host} ssh host remote 远程 连接").to_lowercase(),
|
||||
search,
|
||||
action: WorkspacePaletteAction::LaunchSshHost(host),
|
||||
icon: None,
|
||||
icon_glyph: Some(glyph),
|
||||
|
||||
@@ -15,13 +15,24 @@ fn fallback_shell_glyph(id: &str, has_brand: bool) -> Option<char> {
|
||||
crate::shell_detect::icon_for_id(id).chars().next()
|
||||
}
|
||||
|
||||
/// SSH 主机的展示名与次要信息,与旧壳 `SshRow` 同口径:
|
||||
///
|
||||
/// - 用户在 SSH 设置里起过"主机名称":label 显示别名,hint 给真实连接地址;
|
||||
/// - 没起名:回落地址本身当 label,hint 保持 "SSH" 类型标签,避免重复。
|
||||
pub(super) fn ssh_host_display(label: Option<&str>, host: &str) -> (String, String) {
|
||||
match label {
|
||||
Some(label) if !label.trim().is_empty() => (label.trim().to_owned(), host.to_owned()),
|
||||
_ => (host.to_owned(), "SSH".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 新建终端弹窗的行:已检测 shell + SSH 主机,分组对照旧壳
|
||||
/// `CommandPalette::open_profiles`(推荐 / 所有 Shell / SSH 主机)。
|
||||
/// 三点菜单与 Ctrl+K 打开的是这份列表,不是通用命令面板。
|
||||
pub(super) fn shell_palette_rows(
|
||||
shells: Vec<crate::shell_detect::DetectedShell>,
|
||||
profiles: Vec<crate::config::ui_config::Profile>,
|
||||
ssh_hosts: impl IntoIterator<Item = String>,
|
||||
ssh_hosts: impl IntoIterator<Item = (String, String)>,
|
||||
default_shell_id: &str,
|
||||
language: crate::display::UiLanguage,
|
||||
scale_factor: f32,
|
||||
@@ -85,16 +96,20 @@ pub(super) fn shell_palette_rows(
|
||||
rows.insert(0, default_row);
|
||||
}
|
||||
let ssh_icons = ssh_host_icon_ids(&crate::display::nebula_data_dir());
|
||||
rows.extend(ssh_hosts.into_iter().map(|host| {
|
||||
rows.extend(ssh_hosts.into_iter().map(|(host, label)| {
|
||||
let glyph =
|
||||
crate::display::ui::os_icons::resolve(ssh_icons.get(&host).map(String::as_str)).glyph;
|
||||
// 空串 = 没起名:`ssh_host_display` 回落地址本身,hint 保持 "SSH"。
|
||||
let named = (!label.is_empty()).then_some(label.as_str());
|
||||
let (label, hint) = ssh_host_display(named, &host);
|
||||
let search = format!("{label} {host} ssh host remote lianjie 连接").to_lowercase();
|
||||
WorkspacePaletteRow {
|
||||
group_order: 2,
|
||||
group: ssh_group.to_owned(),
|
||||
label: host.clone(),
|
||||
hint: "SSH".to_owned(),
|
||||
label,
|
||||
hint,
|
||||
hint_style: WorkspacePaletteHintStyle::Metadata,
|
||||
search: format!("{host} ssh host remote lianjie 连接").to_lowercase(),
|
||||
search,
|
||||
action: WorkspacePaletteAction::LaunchSshHost(host),
|
||||
icon: None,
|
||||
icon_glyph: Some(glyph),
|
||||
|
||||
@@ -556,7 +556,7 @@ fn shell_palette_puts_the_default_shell_first() {
|
||||
let rows = shell_palette_rows(
|
||||
shells.clone(),
|
||||
Vec::new(),
|
||||
["box.example".to_owned()],
|
||||
[("box.example".to_owned(), String::new())],
|
||||
"nu",
|
||||
language,
|
||||
1.0,
|
||||
@@ -583,7 +583,14 @@ fn shell_palette_puts_the_default_shell_first() {
|
||||
assert_eq!(rows[4].group, "SSH 主机");
|
||||
|
||||
// 默认 id 没在检测结果里(WSL 发行版被卸载等):不置顶也不 panic。
|
||||
let rows = shell_palette_rows(shells, Vec::new(), None::<String>, "wsl:Ghost", language, 1.0);
|
||||
let rows = shell_palette_rows(
|
||||
shells,
|
||||
Vec::new(),
|
||||
None::<(String, String)>,
|
||||
"wsl:Ghost",
|
||||
language,
|
||||
1.0,
|
||||
);
|
||||
assert!(matches!(
|
||||
&rows[0].action,
|
||||
WorkspacePaletteAction::LaunchShell(shell) if shell.id == "pwsh"
|
||||
@@ -591,6 +598,42 @@ fn shell_palette_puts_the_default_shell_first() {
|
||||
assert_eq!(rows[0].group, "所有 Shell");
|
||||
}
|
||||
|
||||
/// 启动器 SSH 行的"主机名称":起过名的显示别名、hint 给真实地址;没起名
|
||||
/// 回落地址本身、hint 保持 "SSH"。搜索词必须同时覆盖别名与地址。
|
||||
#[test]
|
||||
fn shell_palette_ssh_rows_show_the_configured_host_name() {
|
||||
let rows = shell_palette_rows(
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
[
|
||||
("root@box.example".to_owned(), "生产机".to_owned()),
|
||||
("plain.example".to_owned(), String::new()),
|
||||
],
|
||||
"cmd",
|
||||
crate::display::UiLanguage::ZhCn,
|
||||
1.0,
|
||||
);
|
||||
assert_eq!(rows.len(), 2);
|
||||
|
||||
let named = &rows[0];
|
||||
assert_eq!(named.label, "生产机");
|
||||
assert_eq!(named.hint, "root@box.example");
|
||||
assert!(named.search.contains("生产机"));
|
||||
assert!(named.search.contains("root@box.example"));
|
||||
assert!(matches!(
|
||||
&named.action,
|
||||
WorkspacePaletteAction::LaunchSshHost(host) if host == "root@box.example"
|
||||
));
|
||||
|
||||
let plain = &rows[1];
|
||||
assert_eq!(plain.label, "plain.example");
|
||||
assert_eq!(plain.hint, "SSH");
|
||||
assert!(matches!(
|
||||
&plain.action,
|
||||
WorkspacePaletteAction::LaunchSshHost(host) if host == "plain.example"
|
||||
));
|
||||
}
|
||||
|
||||
/// 回归锁:新建终端弹窗里,没有品牌贴图的 shell 不能空着——必须回落到按 id
|
||||
/// 取字的 Nerd Font 字形。之前这一列只填了 `icon`,于是 zsh、csh、ksh 这些
|
||||
/// 整行左边什么都没有。
|
||||
@@ -608,7 +651,7 @@ fn shell_palette_falls_back_to_an_id_glyph_when_brand_art_is_absent() {
|
||||
let rows = shell_palette_rows(
|
||||
shells,
|
||||
Vec::new(),
|
||||
None::<String>,
|
||||
None::<(String, String)>,
|
||||
"zsh",
|
||||
crate::display::UiLanguage::ZhCn,
|
||||
1.0,
|
||||
@@ -649,7 +692,7 @@ fn shell_palette_includes_imported_terminal_profiles() {
|
||||
let rows = shell_palette_rows(
|
||||
Vec::new(),
|
||||
vec![profile],
|
||||
None::<String>,
|
||||
None::<(String, String)>,
|
||||
&id,
|
||||
crate::display::UiLanguage::ZhCn,
|
||||
1.0,
|
||||
|
||||
Reference in new issue
Block a user